Browse Source

Text: API-independent base for glyph caches.

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
Vladimír Vondruš 7 years ago
parent
commit
834c5fe40d
  1. 4
      CMakeLists.txt
  2. 4
      doc/building.dox
  3. 9
      doc/changelog.dox
  4. 2
      doc/custom-buildsystems-order.dot
  5. 9
      modules/FindMagnum.cmake
  6. 18
      src/Magnum/Text/AbstractFont.cpp
  7. 14
      src/Magnum/Text/AbstractFont.h
  8. 40
      src/Magnum/Text/AbstractFontConverter.cpp
  9. 38
      src/Magnum/Text/AbstractFontConverter.h
  10. 76
      src/Magnum/Text/AbstractGlyphCache.cpp
  11. 203
      src/Magnum/Text/AbstractGlyphCache.h
  12. 81
      src/Magnum/Text/CMakeLists.txt
  13. 2
      src/Magnum/Text/DistanceFieldGlyphCache.cpp
  14. 20
      src/Magnum/Text/DistanceFieldGlyphCache.h
  15. 65
      src/Magnum/Text/GlyphCache.cpp
  16. 115
      src/Magnum/Text/GlyphCache.h
  17. 1
      src/Magnum/Text/Renderer.cpp
  18. 6
      src/Magnum/Text/Renderer.h
  19. 75
      src/Magnum/Text/Test/AbstractFontConverterTest.cpp
  20. 418
      src/Magnum/Text/Test/AbstractFontTest.cpp
  21. 192
      src/Magnum/Text/Test/AbstractGlyphCacheTest.cpp
  22. 7
      src/Magnum/Text/Test/CMakeLists.txt
  23. 44
      src/Magnum/Text/Test/GlyphCacheGLTest.cpp
  24. 4
      src/Magnum/Text/Test/RendererGLTest.cpp
  25. 8
      src/Magnum/Text/Text.h
  26. 2
      src/Magnum/Text/visibility.h
  27. 2
      src/MagnumPlugins/MagnumFont/CMakeLists.txt
  28. 14
      src/MagnumPlugins/MagnumFont/MagnumFont.cpp
  29. 10
      src/MagnumPlugins/MagnumFont/MagnumFont.h
  30. 29
      src/MagnumPlugins/MagnumFont/Test/CMakeLists.txt
  31. 74
      src/MagnumPlugins/MagnumFont/Test/MagnumFontGLTest.cpp
  32. 135
      src/MagnumPlugins/MagnumFont/Test/MagnumFontTest.cpp
  33. 2
      src/MagnumPlugins/MagnumFontConverter/CMakeLists.txt
  34. 10
      src/MagnumPlugins/MagnumFontConverter/MagnumFontConverter.cpp
  35. 8
      src/MagnumPlugins/MagnumFontConverter/MagnumFontConverter.h
  36. 16
      src/MagnumPlugins/MagnumFontConverter/Test/CMakeLists.txt
  37. 38
      src/MagnumPlugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp

4
CMakeLists.txt

@ -89,7 +89,7 @@ option(WITH_ANYIMAGECONVERTER "Build AnyImageConverter plugin" OFF)
option(WITH_ANYSCENEIMPORTER "Build AnySceneImporter plugin" OFF) option(WITH_ANYSCENEIMPORTER "Build AnySceneImporter plugin" OFF)
option(WITH_WAVAUDIOIMPORTER "Build WavAudioImporter plugin" OFF) option(WITH_WAVAUDIOIMPORTER "Build WavAudioImporter plugin" OFF)
option(WITH_MAGNUMFONT "Build MagnumFont plugin" OFF) option(WITH_MAGNUMFONT "Build MagnumFont plugin" OFF)
cmake_dependent_option(WITH_MAGNUMFONTCONVERTER "Build MagnumFontConverter plugin" OFF "NOT TARGET_GLES" OFF) option(WITH_MAGNUMFONTCONVERTER "Build MagnumFontConverter plugin" OFF)
option(WITH_OBJIMPORTER "Build ObjImporter plugin" OFF) option(WITH_OBJIMPORTER "Build ObjImporter plugin" OFF)
cmake_dependent_option(WITH_TGAIMAGECONVERTER "Build TgaImageConverter plugin" OFF "NOT WITH_MAGNUMFONTCONVERTER" ON) cmake_dependent_option(WITH_TGAIMAGECONVERTER "Build TgaImageConverter plugin" OFF "NOT WITH_MAGNUMFONTCONVERTER" ON)
cmake_dependent_option(WITH_TGAIMPORTER "Build TgaImporter plugin" OFF "NOT WITH_MAGNUMFONT" ON) cmake_dependent_option(WITH_TGAIMPORTER "Build TgaImporter plugin" OFF "NOT WITH_MAGNUMFONT" ON)
@ -104,7 +104,7 @@ option(WITH_SHADERS "Build Shaders library" ON)
cmake_dependent_option(WITH_TEXT "Build Text library" ON "NOT WITH_FONTCONVERTER;NOT WITH_MAGNUMFONT;NOT WITH_MAGNUMFONTCONVERTER" ON) cmake_dependent_option(WITH_TEXT "Build Text library" ON "NOT WITH_FONTCONVERTER;NOT WITH_MAGNUMFONT;NOT WITH_MAGNUMFONTCONVERTER" ON)
cmake_dependent_option(WITH_TEXTURETOOLS "Build TextureTools library" ON "NOT WITH_TEXT;NOT WITH_DISTANCEFIELDCONVERTER" ON) cmake_dependent_option(WITH_TEXTURETOOLS "Build TextureTools library" ON "NOT WITH_TEXT;NOT WITH_DISTANCEFIELDCONVERTER" ON)
cmake_dependent_option(WITH_TRADE "Build Trade library" ON "NOT WITH_MESHTOOLS;NOT WITH_PRIMITIVES;NOT WITH_IMAGECONVERTER;NOT WITH_ANYIMAGEIMPORTER;NOT WITH_ANYIMAGECONVERTER;NOT WITH_ANYSCENEIMPORTER;NOT WITH_OBJIMPORTER;NOT WITH_TGAIMAGECONVERTER;NOT WITH_TGAIMPORTER" ON) cmake_dependent_option(WITH_TRADE "Build Trade library" ON "NOT WITH_MESHTOOLS;NOT WITH_PRIMITIVES;NOT WITH_IMAGECONVERTER;NOT WITH_ANYIMAGEIMPORTER;NOT WITH_ANYIMAGECONVERTER;NOT WITH_ANYSCENEIMPORTER;NOT WITH_OBJIMPORTER;NOT WITH_TGAIMAGECONVERTER;NOT WITH_TGAIMPORTER" ON)
cmake_dependent_option(WITH_GL "Build GL library" ON "NOT WITH_SHADERS;NOT WITH_TEXT;NOT WITH_GL_INFO;NOT WITH_ANDROIDAPPLICATION;NOT WITH_WINDOWLESSIOSAPPLICATION;NOT WITH_CGLCONTEXT;NOT WITH_GLXAPPLICATION;NOT WITH_GLXCONTEXT;NOT WITH_XEGLAPPLICATION;NOT WITH_WINDOWLESSWGLAPPLICATION;NOT WITH_GLXCONTEXT;NOT WITH_XEGLAPPLICATION;NOT WITH_WINDOWLESSWGLAPPLICATION;NOT WITH_WGLCONTEXT;NOT WITH_WINDOWLESSWINDOWSEGLAPPLICATION;NOT WITH_GLUTAPPLICATION;NOT WITH_DISTANCEFIELDCONVERTER;NOT WITH_FONTCONVERTER;NOT WITH_IMAGECONVERTER" ON) cmake_dependent_option(WITH_GL "Build GL library" ON "NOT WITH_SHADERS;NOT WITH_GL_INFO;NOT WITH_ANDROIDAPPLICATION;NOT WITH_WINDOWLESSIOSAPPLICATION;NOT WITH_CGLCONTEXT;NOT WITH_GLXAPPLICATION;NOT WITH_GLXCONTEXT;NOT WITH_XEGLAPPLICATION;NOT WITH_WINDOWLESSWGLAPPLICATION;NOT WITH_GLXCONTEXT;NOT WITH_XEGLAPPLICATION;NOT WITH_WINDOWLESSWGLAPPLICATION;NOT WITH_WGLCONTEXT;NOT WITH_WINDOWLESSWINDOWSEGLAPPLICATION;NOT WITH_GLUTAPPLICATION;NOT WITH_DISTANCEFIELDCONVERTER;NOT WITH_FONTCONVERTER;NOT WITH_IMAGECONVERTER" ON)
option(WITH_PRIMITIVES "Builf Primitives library" ON) option(WITH_PRIMITIVES "Builf Primitives library" ON)
option(WITH_VK "Build Vk library" OFF) option(WITH_VK "Build Vk library" OFF)

4
doc/building.dox

@ -502,7 +502,7 @@ specify which parts will be built and which not:
[OpenAL](https://www.openal.org/), not built by default. [OpenAL](https://www.openal.org/), not built by default.
- `WITH_DEBUGTOOLS` --- Build the @ref DebugTools library. - `WITH_DEBUGTOOLS` --- Build the @ref DebugTools library.
- `WITH_GL` --- Build the @ref GL library. Enabled automatically if - `WITH_GL` --- Build the @ref GL library. Enabled automatically if
`WITH_SHADERS` or `WITH_TEXT` is enabled. `WITH_SHADERS` is enabled.
- `WITH_MESHTOOLS` --- Build the @ref MeshTools library. Enables also - `WITH_MESHTOOLS` --- Build the @ref MeshTools library. Enables also
building of the Trade library. building of the Trade library.
- `WITH_PRIMITIVES` --- Build the @ref Primitives library. Enables also - `WITH_PRIMITIVES` --- Build the @ref Primitives library. Enables also
@ -514,7 +514,7 @@ specify which parts will be built and which not:
- `WITH_SHAPES` @m_class{m-label m-danger} **deprecated** --- Build the - `WITH_SHAPES` @m_class{m-label m-danger} **deprecated** --- Build the
@ref Shapes library. Enables also building of the SceneGraph library. @ref Shapes library. Enables also building of the SceneGraph library.
- `WITH_TEXT` --- Build the @ref Text library. Enables also building of - `WITH_TEXT` --- Build the @ref Text library. Enables also building of
the TextureTools and GL libraries. the TextureTools library.
- `WITH_TEXTURETOOLS` --- Build the @ref TextureTools library. Enabled - `WITH_TEXTURETOOLS` --- Build the @ref TextureTools library. Enabled
automatically if `WITH_TEXT` or `WITH_DISTANCEFIELDCONVERTER` is enabled. automatically if `WITH_TEXT` or `WITH_DISTANCEFIELDCONVERTER` is enabled.
- `WITH_TRADE` --- Build the @ref Trade library. - `WITH_TRADE` --- Build the @ref Trade library.

9
doc/changelog.dox

@ -77,6 +77,15 @@ See also:
- Detection of SwiftShader drivers with - Detection of SwiftShader drivers with
@ref GL::Context::DetectedDriver::SwiftShader @ref GL::Context::DetectedDriver::SwiftShader
@subsubsection changelog-latest-new-text Text library
- A new @ref Text::AbstractGlyphCache base now makes @ref Text::AbstractFont
and @ref Text::AbstractFontConverter independent on the graphics API used,
meaning the @ref Text library now has just an optional dependency on
@ref GL. The @ref Text::Renderer, @ref Text::GlyphCache and
@ref Text::DistanceFieldGlyphCache classes are now built only if
`TARGET_GL` is enabled (done by default).
@subsection changelog-latest-changes Changes and improvements @subsection changelog-latest-changes Changes and improvements
- The @ref ResourceManager class now accepts also - The @ref ResourceManager class now accepts also

2
doc/custom-buildsystems-order.dot

@ -90,7 +90,7 @@ digraph "Magnum library dependency order" {
MagnumShapes -> MagnumSceneGraph [class="m-dim"] MagnumShapes -> MagnumSceneGraph [class="m-dim"]
MagnumText -> MagnumTextureTools MagnumText -> MagnumTextureTools
MagnumText -> MagnumGL MagnumText -> MagnumGL [style=dotted]
MagnumTextureTools -> Magnum MagnumTextureTools -> Magnum
MagnumTextureTools -> MagnumGL [style=dotted] MagnumTextureTools -> MagnumGL [style=dotted]

9
modules/FindMagnum.cmake

@ -398,7 +398,10 @@ set(_MAGNUM_Shaders_DEPENDENCIES GL)
if(MAGNUM_BUILD_DEPRECATED) if(MAGNUM_BUILD_DEPRECATED)
set(_MAGNUM_Shapes_DEPENDENCIES SceneGraph) set(_MAGNUM_Shapes_DEPENDENCIES SceneGraph)
endif() endif()
set(_MAGNUM_Text_DEPENDENCIES TextureTools GL) set(_MAGNUM_Text_DEPENDENCIES TextureTools)
if(MAGNUM_TARGET_GL)
list(APPEND _MAGNUM_Text_DEPENDENCIES GL)
endif()
set(_MAGNUM_TextureTools_DEPENDENCIES ) set(_MAGNUM_TextureTools_DEPENDENCIES )
if(MAGNUM_TARGET_GL) if(MAGNUM_TARGET_GL)
@ -433,7 +436,7 @@ set(_MAGNUM_EglContext_DEPENDENCIES GL)
set(_MAGNUM_GlxContext_DEPENDENCIES GL) set(_MAGNUM_GlxContext_DEPENDENCIES GL)
set(_MAGNUM_WglContext_DEPENDENCIES GL) set(_MAGNUM_WglContext_DEPENDENCIES GL)
set(_MAGNUM_MagnumFont_DEPENDENCIES Trade TgaImporter) # and below set(_MAGNUM_MagnumFont_DEPENDENCIES Trade TgaImporter GL) # and below
set(_MAGNUM_MagnumFontConverter_DEPENDENCIES Trade TgaImageConverter) # and below set(_MAGNUM_MagnumFontConverter_DEPENDENCIES Trade TgaImageConverter) # and below
set(_MAGNUM_ObjImporter_DEPENDENCIES MeshTools) # and below set(_MAGNUM_ObjImporter_DEPENDENCIES MeshTools) # and below
foreach(_component ${_MAGNUM_PLUGIN_COMPONENT_LIST}) foreach(_component ${_MAGNUM_PLUGIN_COMPONENT_LIST})
@ -442,7 +445,7 @@ foreach(_component ${_MAGNUM_PLUGIN_COMPONENT_LIST})
elseif(_component MATCHES ".+(Importer|ImageConverter)") elseif(_component MATCHES ".+(Importer|ImageConverter)")
list(APPEND _MAGNUM_${_component}_DEPENDENCIES Trade) list(APPEND _MAGNUM_${_component}_DEPENDENCIES Trade)
elseif(_component MATCHES ".+(Font|FontConverter)") elseif(_component MATCHES ".+(Font|FontConverter)")
list(APPEND _MAGNUM_${_component}_DEPENDENCIES Text TextureTools GL) list(APPEND _MAGNUM_${_component}_DEPENDENCIES Text TextureTools)
endif() endif()
endforeach() endforeach()

18
src/Magnum/Text/AbstractFont.cpp

@ -30,7 +30,7 @@
#include <Corrade/Utility/Unicode.h> #include <Corrade/Utility/Unicode.h>
#include "Magnum/Math/Functions.h" #include "Magnum/Math/Functions.h"
#include "Magnum/Text/GlyphCache.h" #include "Magnum/Text/AbstractGlyphCache.h"
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
#include "Magnum/Text/configure.h" #include "Magnum/Text/configure.h"
@ -39,7 +39,7 @@
namespace Magnum { namespace Text { namespace Magnum { namespace Text {
std::string AbstractFont::pluginInterface() { std::string AbstractFont::pluginInterface() {
return "cz.mosra.magnum.Text.AbstractFont/0.2.4"; return "cz.mosra.magnum.Text.AbstractFont/0.3";
} }
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
@ -125,7 +125,7 @@ auto AbstractFont::doOpenFile(const std::string& filename, const Float size) ->
/* Open file */ /* Open file */
if(!Utility::Directory::exists(filename)) { if(!Utility::Directory::exists(filename)) {
Error() << "Trade::AbstractFont::openFile(): cannot open file" << filename; Error() << "Text::AbstractFont::openFile(): cannot open file" << filename;
return {}; return {};
} }
@ -153,20 +153,20 @@ Vector2 AbstractFont::glyphAdvance(const UnsignedInt glyph) {
return doGlyphAdvance(glyph); return doGlyphAdvance(glyph);
} }
void AbstractFont::fillGlyphCache(GlyphCache& cache, const std::string& characters) { void AbstractFont::fillGlyphCache(AbstractGlyphCache& cache, const std::string& characters) {
CORRADE_ASSERT(isOpened(), CORRADE_ASSERT(isOpened(),
"Text::AbstractFont::createGlyphCache(): no font opened", ); "Text::AbstractFont::fillGlyphCache(): no font opened", );
CORRADE_ASSERT(!(features() & Feature::PreparedGlyphCache), CORRADE_ASSERT(!(features() & Feature::PreparedGlyphCache),
"Text::AbstractFont::fillGlyphCache(): feature not supported", ); "Text::AbstractFont::fillGlyphCache(): feature not supported", );
doFillGlyphCache(cache, Utility::Unicode::utf32(characters)); doFillGlyphCache(cache, Utility::Unicode::utf32(characters));
} }
void AbstractFont::doFillGlyphCache(GlyphCache&, const std::u32string&) { void AbstractFont::doFillGlyphCache(AbstractGlyphCache&, const std::u32string&) {
CORRADE_ASSERT(false, "Text::AbstractFont::fillGlyphCache(): feature advertised but not implemented", ); CORRADE_ASSERT(false, "Text::AbstractFont::fillGlyphCache(): feature advertised but not implemented", );
} }
Containers::Pointer<GlyphCache> AbstractFont::createGlyphCache() { Containers::Pointer<AbstractGlyphCache> AbstractFont::createGlyphCache() {
CORRADE_ASSERT(isOpened(), CORRADE_ASSERT(isOpened(),
"Text::AbstractFont::createGlyphCache(): no font opened", nullptr); "Text::AbstractFont::createGlyphCache(): no font opened", nullptr);
CORRADE_ASSERT(features() & Feature::PreparedGlyphCache, CORRADE_ASSERT(features() & Feature::PreparedGlyphCache,
@ -175,12 +175,12 @@ Containers::Pointer<GlyphCache> AbstractFont::createGlyphCache() {
return doCreateGlyphCache(); return doCreateGlyphCache();
} }
Containers::Pointer<GlyphCache> AbstractFont::doCreateGlyphCache() { Containers::Pointer<AbstractGlyphCache> AbstractFont::doCreateGlyphCache() {
CORRADE_ASSERT(false, "Text::AbstractFont::createGlyphCache(): feature advertised but not implemented", nullptr); CORRADE_ASSERT(false, "Text::AbstractFont::createGlyphCache(): feature advertised but not implemented", nullptr);
return nullptr; return nullptr;
} }
Containers::Pointer<AbstractLayouter> AbstractFont::layout(const GlyphCache& cache, const Float size, const std::string& text) { Containers::Pointer<AbstractLayouter> AbstractFont::layout(const AbstractGlyphCache& cache, const Float size, const std::string& text) {
CORRADE_ASSERT(isOpened(), "Text::AbstractFont::layout(): no font opened", nullptr); CORRADE_ASSERT(isOpened(), "Text::AbstractFont::layout(): no font opened", nullptr);
return doLayout(cache, size, text); return doLayout(cache, size, text);

14
src/Magnum/Text/AbstractFont.h

@ -108,7 +108,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* @brief Plugin interface * @brief Plugin interface
* *
* @code{.cpp} * @code{.cpp}
* "cz.mosra.magnum.Text.AbstractFont/0.2.4" * "cz.mosra.magnum.Text.AbstractFont/0.3"
* @endcode * @endcode
*/ */
static std::string pluginInterface(); static std::string pluginInterface();
@ -244,7 +244,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* @ref Feature::PreparedGlyphCache do not support partial glyph cache * @ref Feature::PreparedGlyphCache do not support partial glyph cache
* filling, use @ref createGlyphCache() instead. * filling, use @ref createGlyphCache() instead.
*/ */
void fillGlyphCache(GlyphCache& cache, const std::string& characters); void fillGlyphCache(AbstractGlyphCache& cache, const std::string& characters);
/** /**
* @brief Create glyph cache * @brief Create glyph cache
@ -254,7 +254,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* Other fonts support only partial glyph cache filling, see * Other fonts support only partial glyph cache filling, see
* @ref fillGlyphCache(). * @ref fillGlyphCache().
*/ */
Containers::Pointer<GlyphCache> createGlyphCache(); Containers::Pointer<AbstractGlyphCache> createGlyphCache();
/** /**
* @brief Layout the text using font's own layouter * @brief Layout the text using font's own layouter
@ -266,7 +266,7 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* See @ref Renderer class for more advanced text layouting. * See @ref Renderer class for more advanced text layouting.
* @see @ref fillGlyphCache(), @ref createGlyphCache() * @see @ref fillGlyphCache(), @ref createGlyphCache()
*/ */
Containers::Pointer<AbstractLayouter> layout(const GlyphCache& cache, Float size, const std::string& text); Containers::Pointer<AbstractLayouter> layout(const AbstractGlyphCache& cache, Float size, const std::string& text);
protected: protected:
/** /**
@ -349,13 +349,13 @@ class MAGNUM_TEXT_EXPORT AbstractFont: public PluginManager::AbstractPlugin {
* The string is converted from UTF-8 to UTF-32, unique characters are * The string is converted from UTF-8 to UTF-32, unique characters are
* *not* removed. * *not* removed.
*/ */
virtual void doFillGlyphCache(GlyphCache& cache, const std::u32string& characters); virtual void doFillGlyphCache(AbstractGlyphCache& cache, const std::u32string& characters);
/** @brief Implementation for @ref createGlyphCache() */ /** @brief Implementation for @ref createGlyphCache() */
virtual Containers::Pointer<GlyphCache> doCreateGlyphCache(); virtual Containers::Pointer<AbstractGlyphCache> doCreateGlyphCache();
/** @brief Implementation for @ref layout() */ /** @brief Implementation for @ref layout() */
virtual Containers::Pointer<AbstractLayouter> doLayout(const GlyphCache& cache, Float size, const std::string& text) = 0; virtual Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache& cache, Float size, const std::string& text) = 0;
#ifdef DOXYGEN_GENERATING_OUTPUT #ifdef DOXYGEN_GENERATING_OUTPUT
private: private:

40
src/Magnum/Text/AbstractFontConverter.cpp

@ -31,7 +31,7 @@
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/Unicode.h> #include <Corrade/Utility/Unicode.h>
#include "Magnum/Text/GlyphCache.h" #include "Magnum/Text/AbstractGlyphCache.h"
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
#include "Magnum/Text/configure.h" #include "Magnum/Text/configure.h"
@ -56,7 +56,7 @@ std::u32string uniqueUnicode(const std::string& characters)
} }
std::string AbstractFontConverter::pluginInterface() { std::string AbstractFontConverter::pluginInterface() {
return "cz.mosra.magnum.Text.AbstractFontConverter/0.1.2"; return "cz.mosra.magnum.Text.AbstractFontConverter/0.2";
} }
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
@ -77,14 +77,14 @@ AbstractFontConverter::AbstractFontConverter() = default;
AbstractFontConverter::AbstractFontConverter(PluginManager::AbstractManager& manager, const std::string& plugin): PluginManager::AbstractPlugin{manager, plugin} {} AbstractFontConverter::AbstractFontConverter(PluginManager::AbstractManager& manager, const std::string& plugin): PluginManager::AbstractPlugin{manager, plugin} {}
std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::exportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::string& characters) const { std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::exportFontToData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::string& characters) const {
CORRADE_ASSERT(features() >= (Feature::ExportFont|Feature::ConvertData), CORRADE_ASSERT(features() >= (Feature::ExportFont|Feature::ConvertData),
"Text::AbstractFontConverter::exportFontToData(): feature not supported", {}); "Text::AbstractFontConverter::exportFontToData(): feature not supported", {});
return doExportFontToData(font, cache, filename, uniqueUnicode(characters)); return doExportFontToData(font, cache, filename, uniqueUnicode(characters));
} }
std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const { std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::doExportFontToData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::u32string& characters) const {
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
"Text::AbstractFontConverter::exportFontToData(): feature advertised but not implemented", {}); "Text::AbstractFontConverter::exportFontToData(): feature advertised but not implemented", {});
@ -93,7 +93,7 @@ std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConvert
return out; return out;
} }
Containers::Array<char> AbstractFontConverter::exportFontToSingleData(AbstractFont& font, GlyphCache& cache, const std::string& characters) const { Containers::Array<char> AbstractFontConverter::exportFontToSingleData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& characters) const {
CORRADE_ASSERT(features() >= (Feature::ExportFont|Feature::ConvertData), CORRADE_ASSERT(features() >= (Feature::ExportFont|Feature::ConvertData),
"Text::AbstractFontConverter::exportFontToSingleData(): feature not supported", nullptr); "Text::AbstractFontConverter::exportFontToSingleData(): feature not supported", nullptr);
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
@ -102,20 +102,20 @@ Containers::Array<char> AbstractFontConverter::exportFontToSingleData(AbstractFo
return doExportFontToSingleData(font, cache, uniqueUnicode(characters)); return doExportFontToSingleData(font, cache, uniqueUnicode(characters));
} }
Containers::Array<char> AbstractFontConverter::doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string&) const { Containers::Array<char> AbstractFontConverter::doExportFontToSingleData(AbstractFont&, AbstractGlyphCache&, const std::u32string&) const {
CORRADE_ASSERT(false, CORRADE_ASSERT(false,
"Text::AbstractFontConverter::exportFontToSingleData(): feature advertised but not implemented", nullptr); "Text::AbstractFontConverter::exportFontToSingleData(): feature advertised but not implemented", nullptr);
return nullptr; return nullptr;
} }
bool AbstractFontConverter::exportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::string& characters) const { bool AbstractFontConverter::exportFontToFile(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::string& characters) const {
CORRADE_ASSERT(features() & Feature::ExportFont, CORRADE_ASSERT(features() & Feature::ExportFont,
"Text::AbstractFontConverter::exportFontToFile(): feature not supported", false); "Text::AbstractFontConverter::exportFontToFile(): feature not supported", false);
return doExportFontToFile(font, cache, filename, uniqueUnicode(characters)); return doExportFontToFile(font, cache, filename, uniqueUnicode(characters));
} }
bool AbstractFontConverter::doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const { bool AbstractFontConverter::doExportFontToFile(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::u32string& characters) const {
CORRADE_ASSERT(features() & Feature::ConvertData, CORRADE_ASSERT(features() & Feature::ConvertData,
"Text::AbstractFontConverter::exportFontToFile(): not implemented", false); "Text::AbstractFontConverter::exportFontToFile(): not implemented", false);
@ -129,14 +129,14 @@ bool AbstractFontConverter::doExportFontToFile(AbstractFont& font, GlyphCache& c
return true; return true;
} }
std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::exportGlyphCacheToData(GlyphCache& cache, const std::string& filename) const { std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::exportGlyphCacheToData(AbstractGlyphCache& cache, const std::string& filename) const {
CORRADE_ASSERT(features() >= (Feature::ExportGlyphCache|Feature::ConvertData), CORRADE_ASSERT(features() >= (Feature::ExportGlyphCache|Feature::ConvertData),
"Text::AbstractFontConverter::exportGlyphCacheToData(): feature not supported", {}); "Text::AbstractFontConverter::exportGlyphCacheToData(): feature not supported", {});
return doExportGlyphCacheToData(cache, filename); return doExportGlyphCacheToData(cache, filename);
} }
std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::doExportGlyphCacheToData(GlyphCache& cache, const std::string& filename) const { std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConverter::doExportGlyphCacheToData(AbstractGlyphCache& cache, const std::string& filename) const {
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
"Text::AbstractFontConverter::exportGlyphCacheToData(): feature advertised but not implemented", {}); "Text::AbstractFontConverter::exportGlyphCacheToData(): feature advertised but not implemented", {});
@ -145,7 +145,7 @@ std::vector<std::pair<std::string, Containers::Array<char>>> AbstractFontConvert
return out; return out;
} }
Containers::Array<char> AbstractFontConverter::exportGlyphCacheToSingleData(GlyphCache& cache) const { Containers::Array<char> AbstractFontConverter::exportGlyphCacheToSingleData(AbstractGlyphCache& cache) const {
CORRADE_ASSERT(features() >= (Feature::ExportGlyphCache|Feature::ConvertData), CORRADE_ASSERT(features() >= (Feature::ExportGlyphCache|Feature::ConvertData),
"Text::AbstractFontConverter::exportGlyphCacheToSingleData(): feature not supported", nullptr); "Text::AbstractFontConverter::exportGlyphCacheToSingleData(): feature not supported", nullptr);
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
@ -154,20 +154,20 @@ Containers::Array<char> AbstractFontConverter::exportGlyphCacheToSingleData(Glyp
return doExportGlyphCacheToSingleData(cache); return doExportGlyphCacheToSingleData(cache);
} }
Containers::Array<char> AbstractFontConverter::doExportGlyphCacheToSingleData(GlyphCache&) const { Containers::Array<char> AbstractFontConverter::doExportGlyphCacheToSingleData(AbstractGlyphCache&) const {
CORRADE_ASSERT(false, CORRADE_ASSERT(false,
"Text::AbstractFontConverter::exportGlyphCacheToSingleData(): feature advertised but not implemented", nullptr); "Text::AbstractFontConverter::exportGlyphCacheToSingleData(): feature advertised but not implemented", nullptr);
return nullptr; return nullptr;
} }
bool AbstractFontConverter::exportGlyphCacheToFile(GlyphCache& cache, const std::string& filename) const { bool AbstractFontConverter::exportGlyphCacheToFile(AbstractGlyphCache& cache, const std::string& filename) const {
CORRADE_ASSERT(features() & Feature::ExportGlyphCache, CORRADE_ASSERT(features() & Feature::ExportGlyphCache,
"Text::AbstractFontConverter::exportGlyphCacheToFile(): feature not supported", false); "Text::AbstractFontConverter::exportGlyphCacheToFile(): feature not supported", false);
return doExportGlyphCacheToFile(cache, filename); return doExportGlyphCacheToFile(cache, filename);
} }
bool AbstractFontConverter::doExportGlyphCacheToFile(GlyphCache& cache, const std::string& filename) const { bool AbstractFontConverter::doExportGlyphCacheToFile(AbstractGlyphCache& cache, const std::string& filename) const {
CORRADE_ASSERT(features() & Feature::ConvertData, CORRADE_ASSERT(features() & Feature::ConvertData,
"Text::AbstractFontConverter::exportGlyphCacheToFile(): not implemented", false); "Text::AbstractFontConverter::exportGlyphCacheToFile(): not implemented", false);
@ -181,7 +181,7 @@ bool AbstractFontConverter::doExportGlyphCacheToFile(GlyphCache& cache, const st
return true; return true;
} }
Containers::Pointer<GlyphCache> AbstractFontConverter::importGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const { Containers::Pointer<AbstractGlyphCache> AbstractFontConverter::importGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const {
CORRADE_ASSERT(features() >= (Feature::ImportGlyphCache|Feature::ConvertData), CORRADE_ASSERT(features() >= (Feature::ImportGlyphCache|Feature::ConvertData),
"Text::AbstractFontConverter::importGlyphCacheFromData(): feature not supported", nullptr); "Text::AbstractFontConverter::importGlyphCacheFromData(): feature not supported", nullptr);
CORRADE_ASSERT(!data.empty(), CORRADE_ASSERT(!data.empty(),
@ -190,7 +190,7 @@ Containers::Pointer<GlyphCache> AbstractFontConverter::importGlyphCacheFromData(
return doImportGlyphCacheFromData(data); return doImportGlyphCacheFromData(data);
} }
Containers::Pointer<GlyphCache> AbstractFontConverter::doImportGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const { Containers::Pointer<AbstractGlyphCache> AbstractFontConverter::doImportGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const {
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
"Text::AbstractFontConverter::importGlyphCacheFromData(): feature advertised but not implemented", nullptr); "Text::AbstractFontConverter::importGlyphCacheFromData(): feature advertised but not implemented", nullptr);
CORRADE_ASSERT(data.size() == 1, CORRADE_ASSERT(data.size() == 1,
@ -199,7 +199,7 @@ Containers::Pointer<GlyphCache> AbstractFontConverter::doImportGlyphCacheFromDat
return doImportGlyphCacheFromSingleData(data[0].second); return doImportGlyphCacheFromSingleData(data[0].second);
} }
Containers::Pointer<GlyphCache> AbstractFontConverter::importGlyphCacheFromSingleData(Containers::ArrayView<const char> data) const { Containers::Pointer<AbstractGlyphCache> AbstractFontConverter::importGlyphCacheFromSingleData(Containers::ArrayView<const char> data) const {
CORRADE_ASSERT(features() >= (Feature::ImportGlyphCache|Feature::ConvertData), CORRADE_ASSERT(features() >= (Feature::ImportGlyphCache|Feature::ConvertData),
"Text::AbstractFontConverter::importGlyphCacheFromSingleData(): feature not supported", nullptr); "Text::AbstractFontConverter::importGlyphCacheFromSingleData(): feature not supported", nullptr);
CORRADE_ASSERT(!(features() & Feature::MultiFile), CORRADE_ASSERT(!(features() & Feature::MultiFile),
@ -208,20 +208,20 @@ Containers::Pointer<GlyphCache> AbstractFontConverter::importGlyphCacheFromSingl
return doImportGlyphCacheFromSingleData(data); return doImportGlyphCacheFromSingleData(data);
} }
Containers::Pointer<GlyphCache> AbstractFontConverter::doImportGlyphCacheFromSingleData(Containers::ArrayView<const char>) const { Containers::Pointer<AbstractGlyphCache> AbstractFontConverter::doImportGlyphCacheFromSingleData(Containers::ArrayView<const char>) const {
CORRADE_ASSERT(false, CORRADE_ASSERT(false,
"Text::AbstractFontConverter::importGlyphCacheFromSingleData(): feature advertised but not implemented", nullptr); "Text::AbstractFontConverter::importGlyphCacheFromSingleData(): feature advertised but not implemented", nullptr);
return nullptr; return nullptr;
} }
Containers::Pointer<GlyphCache> AbstractFontConverter::importGlyphCacheFromFile(const std::string& filename) const { Containers::Pointer<AbstractGlyphCache> AbstractFontConverter::importGlyphCacheFromFile(const std::string& filename) const {
CORRADE_ASSERT(features() & Feature::ImportGlyphCache, CORRADE_ASSERT(features() & Feature::ImportGlyphCache,
"Text::AbstractFontConverter::importGlyphCacheFromFile(): feature not supported", nullptr); "Text::AbstractFontConverter::importGlyphCacheFromFile(): feature not supported", nullptr);
return doImportGlyphCacheFromFile(filename); return doImportGlyphCacheFromFile(filename);
} }
Containers::Pointer<GlyphCache> AbstractFontConverter::doImportGlyphCacheFromFile(const std::string& filename) const { Containers::Pointer<AbstractGlyphCache> AbstractFontConverter::doImportGlyphCacheFromFile(const std::string& filename) const {
CORRADE_ASSERT(features() & Feature::ConvertData && !(features() & Feature::MultiFile), CORRADE_ASSERT(features() & Feature::ConvertData && !(features() & Feature::MultiFile),
"Text::AbstractFontConverter::importGlyphCacheFromFile(): not implemented", nullptr); "Text::AbstractFontConverter::importGlyphCacheFromFile(): not implemented", nullptr);

38
src/Magnum/Text/AbstractFontConverter.h

@ -134,7 +134,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @brief Plugin interface * @brief Plugin interface
* *
* @code{.cpp} * @code{.cpp}
* "cz.mosra.magnum.Text.AbstractFontConverter/0.1.2" * "cz.mosra.magnum.Text.AbstractFontConverter/0.2"
* @endcode * @endcode
*/ */
static std::string pluginInterface(); static std::string pluginInterface();
@ -182,7 +182,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref exportFontToFile(), * @see @ref features(), @ref exportFontToFile(),
* @ref exportGlyphCacheToData() * @ref exportGlyphCacheToData()
*/ */
std::vector<std::pair<std::string, Containers::Array<char>>> exportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::string& characters) const; std::vector<std::pair<std::string, Containers::Array<char>>> exportFontToData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::string& characters) const;
/** /**
* @brief Export font to single raw data * @brief Export font to single raw data
@ -194,7 +194,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref exportFontToFile(), * @see @ref features(), @ref exportFontToFile(),
* @ref exportGlyphCacheToSingleData() * @ref exportGlyphCacheToSingleData()
*/ */
Containers::Array<char> exportFontToSingleData(AbstractFont& font, GlyphCache& cache, const std::string& characters) const; Containers::Array<char> exportFontToSingleData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& characters) const;
/** /**
* @brief Export font to file * @brief Export font to file
@ -207,7 +207,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref exportFontToData(), * @see @ref features(), @ref exportFontToData(),
* @ref exportGlyphCacheToFile() * @ref exportGlyphCacheToFile()
*/ */
bool exportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::string& characters) const; bool exportFontToFile(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::string& characters) const;
/** /**
* @brief Export glyph cache to raw data * @brief Export glyph cache to raw data
@ -226,7 +226,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref exportGlyphCacheToFile(), * @see @ref features(), @ref exportGlyphCacheToFile(),
* @ref exportFontToData() * @ref exportFontToData()
*/ */
std::vector<std::pair<std::string, Containers::Array<char>>> exportGlyphCacheToData(GlyphCache& cache, const std::string& filename) const; std::vector<std::pair<std::string, Containers::Array<char>>> exportGlyphCacheToData(AbstractGlyphCache& cache, const std::string& filename) const;
/** /**
* @brief Export glyph cache to single raw data * @brief Export glyph cache to single raw data
@ -238,7 +238,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref exportGlyphCacheToFile(), * @see @ref features(), @ref exportGlyphCacheToFile(),
* @ref importGlyphCacheFromSingleData() * @ref importGlyphCacheFromSingleData()
*/ */
Containers::Array<char> exportGlyphCacheToSingleData(GlyphCache& cache) const; Containers::Array<char> exportGlyphCacheToSingleData(AbstractGlyphCache& cache) const;
/** /**
* @brief Export glyph cache to file * @brief Export glyph cache to file
@ -251,7 +251,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref exportGlyphCacheToData(), * @see @ref features(), @ref exportGlyphCacheToData(),
* @ref exportFontToFile() * @ref exportFontToFile()
*/ */
bool exportGlyphCacheToFile(GlyphCache& cache, const std::string& filename) const; bool exportGlyphCacheToFile(AbstractGlyphCache& cache, const std::string& filename) const;
/** /**
* @brief Import glyph cache from raw data * @brief Import glyph cache from raw data
@ -265,7 +265,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref importGlyphCacheFromFile(), * @see @ref features(), @ref importGlyphCacheFromFile(),
* @ref exportGlyphCacheToData() * @ref exportGlyphCacheToData()
*/ */
Containers::Pointer<GlyphCache> importGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const; Containers::Pointer<AbstractGlyphCache> importGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const;
/** /**
* @brief Import glyph cache from single raw data * @brief Import glyph cache from single raw data
@ -277,7 +277,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref importGlyphCacheFromFile(), * @see @ref features(), @ref importGlyphCacheFromFile(),
* @ref exportFontToSingleData() * @ref exportFontToSingleData()
*/ */
Containers::Pointer<GlyphCache> importGlyphCacheFromSingleData(Containers::ArrayView<const char> data) const; Containers::Pointer<AbstractGlyphCache> importGlyphCacheFromSingleData(Containers::ArrayView<const char> data) const;
/** /**
* @brief Import glyph cache from file * @brief Import glyph cache from file
@ -290,7 +290,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* @see @ref features(), @ref importGlyphCacheFromData(), * @see @ref features(), @ref importGlyphCacheFromData(),
* @ref exportGlyphCacheToFile() * @ref exportGlyphCacheToFile()
*/ */
Containers::Pointer<GlyphCache> importGlyphCacheFromFile(const std::string& filename) const; Containers::Pointer<AbstractGlyphCache> importGlyphCacheFromFile(const std::string& filename) const;
private: private:
/** @brief Implementation for @ref features() */ /** @brief Implementation for @ref features() */
@ -302,10 +302,10 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* If the plugin doesn't have @ref Feature::MultiFile, default * If the plugin doesn't have @ref Feature::MultiFile, default
* implementation calls @ref doExportFontToSingleData(). * implementation calls @ref doExportFontToSingleData().
*/ */
virtual std::vector<std::pair<std::string, Containers::Array<char>>> doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const; virtual std::vector<std::pair<std::string, Containers::Array<char>>> doExportFontToData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::u32string& characters) const;
/** @brief Implementation for @ref exportFontToSingleData() */ /** @brief Implementation for @ref exportFontToSingleData() */
virtual Containers::Array<char> doExportFontToSingleData(AbstractFont& font, GlyphCache& cache, const std::u32string& characters) const; virtual Containers::Array<char> doExportFontToSingleData(AbstractFont& font, AbstractGlyphCache& cache, const std::u32string& characters) const;
/** /**
* @brief Implementation for @ref exportFontToFile() * @brief Implementation for @ref exportFontToFile()
@ -314,7 +314,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* calls @ref doExportFontToData() and saves the result to given * calls @ref doExportFontToData() and saves the result to given
* file(s). * file(s).
*/ */
virtual bool doExportFontToFile(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const; virtual bool doExportFontToFile(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::u32string& characters) const;
/** /**
* @brief Implementation for @ref exportGlyphCacheToData() * @brief Implementation for @ref exportGlyphCacheToData()
@ -322,10 +322,10 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* If the plugin doesn't have @ref Feature::MultiFile, default * If the plugin doesn't have @ref Feature::MultiFile, default
* implementation calls @ref doExportGlyphCacheToSingleData(). * implementation calls @ref doExportGlyphCacheToSingleData().
*/ */
virtual std::vector<std::pair<std::string, Containers::Array<char>>> doExportGlyphCacheToData(GlyphCache& cache, const std::string& filename) const; virtual std::vector<std::pair<std::string, Containers::Array<char>>> doExportGlyphCacheToData(AbstractGlyphCache& cache, const std::string& filename) const;
/** @brief Implementation for @ref exportGlyphCacheToSingleData() */ /** @brief Implementation for @ref exportGlyphCacheToSingleData() */
virtual Containers::Array<char> doExportGlyphCacheToSingleData(GlyphCache& cache) const; virtual Containers::Array<char> doExportGlyphCacheToSingleData(AbstractGlyphCache& cache) const;
/** /**
* @brief Implementation for @ref exportGlyphCacheToFile() * @brief Implementation for @ref exportGlyphCacheToFile()
@ -334,7 +334,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* calls @ref doExportGlyphCacheToData() and saves the result to given * calls @ref doExportGlyphCacheToData() and saves the result to given
* file(s). * file(s).
*/ */
virtual bool doExportGlyphCacheToFile(GlyphCache& cache, const std::string& filename) const; virtual bool doExportGlyphCacheToFile(AbstractGlyphCache& cache, const std::string& filename) const;
/** /**
* @brief Implementation for @ref importGlyphCacheFromData() * @brief Implementation for @ref importGlyphCacheFromData()
@ -342,10 +342,10 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* If the plugin doesn't have @ref Feature::MultiFile, default * If the plugin doesn't have @ref Feature::MultiFile, default
* implementation calls @ref doImportGlyphCacheFromSingleData(). * implementation calls @ref doImportGlyphCacheFromSingleData().
*/ */
virtual Containers::Pointer<GlyphCache> doImportGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const; virtual Containers::Pointer<AbstractGlyphCache> doImportGlyphCacheFromData(const std::vector<std::pair<std::string, Containers::ArrayView<const char>>>& data) const;
/** @brief Implementation for @ref importGlyphCacheFromSingleData() */ /** @brief Implementation for @ref importGlyphCacheFromSingleData() */
virtual Containers::Pointer<GlyphCache> doImportGlyphCacheFromSingleData(Containers::ArrayView<const char> data) const; virtual Containers::Pointer<AbstractGlyphCache> doImportGlyphCacheFromSingleData(Containers::ArrayView<const char> data) const;
/** /**
* @brief Implementation for @ref importGlyphCacheFromFile() * @brief Implementation for @ref importGlyphCacheFromFile()
@ -354,7 +354,7 @@ class MAGNUM_TEXT_EXPORT AbstractFontConverter: public PluginManager::AbstractPl
* have @ref Feature::MultiFile, default implementation opens the file * have @ref Feature::MultiFile, default implementation opens the file
* and calls @ref doImportGlyphCacheFromSingleData() with its contents. * and calls @ref doImportGlyphCacheFromSingleData() with its contents.
*/ */
virtual Containers::Pointer<GlyphCache> doImportGlyphCacheFromFile(const std::string& filename) const; virtual Containers::Pointer<AbstractGlyphCache> doImportGlyphCacheFromFile(const std::string& filename) const;
}; };
CORRADE_ENUMSET_OPERATORS(AbstractFontConverter::Features) CORRADE_ENUMSET_OPERATORS(AbstractFontConverter::Features)

76
src/Magnum/Text/AbstractGlyphCache.cpp

@ -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{{}});
}
}}

203
src/Magnum/Text/AbstractGlyphCache.h

@ -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

81
src/Magnum/Text/CMakeLists.txt

@ -25,32 +25,62 @@
find_package(Corrade REQUIRED PluginManager) find_package(Corrade REQUIRED PluginManager)
# Files shared between main library and unit test library
set(MagnumText_SRCS set(MagnumText_SRCS
AbstractFontConverter.cpp)
# Files compiled with different flags for main library and unit test library
set(MagnumText_GracefulAssert_SRCS
AbstractFont.cpp AbstractFont.cpp
AbstractFontConverter.cpp AbstractGlyphCache.cpp)
DistanceFieldGlyphCache.cpp
GlyphCache.cpp
Renderer.cpp)
set(MagnumText_HEADERS set(MagnumText_HEADERS
AbstractFont.h AbstractFont.h
AbstractFontConverter.h AbstractFontConverter.h
AbstractGlyphCache.h
Alignment.h Alignment.h
DistanceFieldGlyphCache.h
GlyphCache.h
Renderer.h
Text.h Text.h
visibility.h) visibility.h)
if(TARGET_GL)
list(APPEND MagnumText_SRCS
DistanceFieldGlyphCache.cpp
GlyphCache.cpp
Renderer.cpp)
list(APPEND MagnumText_HEADERS
DistanceFieldGlyphCache.h
GlyphCache.h
Renderer.h)
endif()
if(NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT) if(NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h) ${CMAKE_CURRENT_BINARY_DIR}/configure.h)
endif() endif()
# Text library # Objects shared between main and test library
add_library(MagnumText ${SHARED_OR_STATIC} add_library(MagnumTextObjects OBJECT
${MagnumText_SRCS} ${MagnumText_SRCS}
${MagnumText_HEADERS}) ${MagnumText_HEADERS})
target_include_directories(MagnumTextObjects PUBLIC
$<TARGET_PROPERTY:Corrade::PluginManager,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:Magnum,INTERFACE_INCLUDE_DIRECTORIES>)
if(TARGET_GL)
target_include_directories(MagnumTextObjects PUBLIC $<TARGET_PROPERTY:MagnumGL,INTERFACE_INCLUDE_DIRECTORIES>)
endif()
if(NOT BUILD_STATIC)
target_compile_definitions(MagnumTextObjects PRIVATE "MagnumTextObjects_EXPORTS")
endif()
if(NOT BUILD_STATIC OR BUILD_STATIC_PIC)
set_target_properties(MagnumTextObjects PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
set_target_properties(MagnumTextObjects PROPERTIES FOLDER "Magnum/Text")
# Text library
add_library(MagnumText ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumTextObjects>
${MagnumText_GracefulAssert_SRCS})
set_target_properties(MagnumText PROPERTIES set_target_properties(MagnumText PROPERTIES
DEBUG_POSTFIX "-d" DEBUG_POSTFIX "-d"
FOLDER "Magnum/Text") FOLDER "Magnum/Text")
@ -61,9 +91,11 @@ elseif(BUILD_STATIC_PIC)
endif() endif()
target_link_libraries(MagnumText PUBLIC target_link_libraries(MagnumText PUBLIC
Magnum Magnum
MagnumGL
MagnumTextureTools MagnumTextureTools
Corrade::PluginManager) Corrade::PluginManager)
if(TARGET_GL)
target_link_libraries(MagnumText PUBLIC MagnumGL)
endif()
install(TARGETS MagnumText install(TARGETS MagnumText
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR} RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
@ -107,6 +139,35 @@ if(WITH_FONTCONVERTER)
endif() endif()
if(BUILD_TESTS) if(BUILD_TESTS)
# Library with graceful assert for testing
add_library(MagnumTextTestLib ${SHARED_OR_STATIC}
$<TARGET_OBJECTS:MagnumTextObjects>
${MagnumText_GracefulAssert_SRCS})
set_target_properties(MagnumTextTestLib PROPERTIES
DEBUG_POSTFIX "-d"
FOLDER "Magnum/Text")
target_compile_definitions(MagnumTextTestLib PRIVATE
"CORRADE_GRACEFUL_ASSERT" "MagnumText_EXPORTS")
if(BUILD_STATIC_PIC)
set_target_properties(MagnumTextTestLib PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
target_link_libraries(MagnumTextTestLib PUBLIC
Magnum
MagnumTextureTools
Corrade::PluginManager)
if(TARGET_GL)
target_link_libraries(MagnumText PUBLIC MagnumGL)
endif()
# On Windows we need to install first and then run the tests to avoid "DLL
# not found" hell, thus we need to install this too
if(CORRADE_TARGET_WINDOWS AND NOT CMAKE_CROSSCOMPILING AND NOT BUILD_STATIC)
install(TARGETS MagnumTextTestLib
RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR}
LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}
ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR})
endif()
add_subdirectory(Test) add_subdirectory(Test)
endif() endif()

2
src/Magnum/Text/DistanceFieldGlyphCache.cpp

@ -59,7 +59,7 @@ DistanceFieldGlyphCache::DistanceFieldGlyphCache(const Vector2i& originalSize, c
#endif #endif
} }
void DistanceFieldGlyphCache::setImage(const Vector2i& offset, const ImageView2D& image) { void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView2D& image) {
GL::Texture2D input; GL::Texture2D input;
input.setWrapping(GL::SamplerWrapping::ClampToEdge) input.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setMinificationFilter(GL::SamplerFilter::Linear) .setMinificationFilter(GL::SamplerFilter::Linear)

20
src/Magnum/Text/DistanceFieldGlyphCache.h

@ -29,6 +29,9 @@
* @brief Class @ref Magnum::Text::DistanceFieldGlyphCache * @brief Class @ref Magnum::Text::DistanceFieldGlyphCache
*/ */
#include "Magnum/configure.h"
#ifdef MAGNUM_TARGET_GL
#include "Magnum/Text/GlyphCache.h" #include "Magnum/Text/GlyphCache.h"
#include "Magnum/TextureTools/DistanceField.h" #include "Magnum/TextureTools/DistanceField.h"
@ -48,6 +51,10 @@ resulting distance field texture.
@snippet MagnumText.cpp DistanceFieldGlyphCache-usage @snippet MagnumText.cpp DistanceFieldGlyphCache-usage
@note This class is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
@see @ref TextureTools::distanceField() @see @ref TextureTools::distanceField()
*/ */
class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache { class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache {
@ -69,14 +76,6 @@ class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache {
*/ */
explicit DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& size, UnsignedInt radius); explicit DistanceFieldGlyphCache(const Vector2i& originalSize, const Vector2i& size, UnsignedInt radius);
/**
* @brief Set cache image
*
* Uploads image for one or more glyphs to given offset in original
* cache texture. The texture is then converted to distance field.
*/
void setImage(const Vector2i& offset, const ImageView2D& image) override;
/** /**
* @brief Set distance field cache image * @brief Set distance field cache image
* *
@ -86,10 +85,15 @@ class MAGNUM_TEXT_EXPORT DistanceFieldGlyphCache: public GlyphCache {
void setDistanceFieldImage(const Vector2i& offset, const ImageView2D& image); void setDistanceFieldImage(const Vector2i& offset, const ImageView2D& image);
private: private:
void doSetImage(const Vector2i& offset, const ImageView2D& image) override;
Vector2 _scale; Vector2 _scale;
TextureTools::DistanceField _distanceField; TextureTools::DistanceField _distanceField;
}; };
}} }}
#else
#error this header is available only in the OpenGL build
#endif
#endif #endif

65
src/Magnum/Text/GlyphCache.cpp

@ -26,6 +26,7 @@
#include "GlyphCache.h" #include "GlyphCache.h"
#include "Magnum/Image.h" #include "Magnum/Image.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/GL/Context.h" #include "Magnum/GL/Context.h"
#include "Magnum/GL/Extensions.h" #include "Magnum/GL/Extensions.h"
#include "Magnum/GL/TextureFormat.h" #include "Magnum/GL/TextureFormat.h"
@ -35,60 +36,46 @@ namespace Magnum { namespace Text {
GlyphCache::GlyphCache(const GL::TextureFormat internalFormat, const Vector2i& size, const Vector2i& padding): GlyphCache{internalFormat, size, size, padding} {} GlyphCache::GlyphCache(const GL::TextureFormat internalFormat, const Vector2i& size, const Vector2i& padding): GlyphCache{internalFormat, size, size, padding} {}
GlyphCache::GlyphCache(const GL::TextureFormat internalFormat, const Vector2i& originalSize, const Vector2i& size, const Vector2i& padding): _size(originalSize), _padding(padding) { GlyphCache::GlyphCache(const GL::TextureFormat internalFormat, const Vector2i& originalSize, const Vector2i& size, const Vector2i& padding): AbstractGlyphCache{originalSize, padding} {
initialize(internalFormat, size); /* Initialize the texture */
_texture.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setStorage(1, internalFormat, size);
} }
GlyphCache::GlyphCache(const Vector2i& size, const Vector2i& padding): GlyphCache{size, size, padding} {} GlyphCache::GlyphCache(const Vector2i& size, const Vector2i& padding): GlyphCache{size, size, padding} {}
GlyphCache::GlyphCache(const Vector2i& originalSize, const Vector2i& size, const Vector2i& padding): _size(originalSize), _padding(padding) { GlyphCache::GlyphCache(const Vector2i& originalSize, const Vector2i& size, const Vector2i& padding): GlyphCache{
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::texture_rg);
#endif
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
const GL::TextureFormat internalFormat = GL::TextureFormat::R8; GL::TextureFormat::R8,
#else #else
const GL::TextureFormat internalFormat = GL::TextureFormat::Luminance; GL::TextureFormat::Luminance,
#endif
originalSize, size, padding}
{
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::texture_rg);
#endif #endif
initialize(internalFormat, size);
} }
GlyphCache::~GlyphCache() = default; GlyphCache::~GlyphCache() = default;
void GlyphCache::initialize(const GL::TextureFormat internalFormat, const Vector2i& size) { GlyphCacheFeatures GlyphCache::doFeatures() const {
/* Initialize texture */ #ifndef MAGNUM_TARGET_GLES
_texture.setWrapping(GL::SamplerWrapping::ClampToEdge) return GlyphCacheFeature::ImageDownload;
.setMinificationFilter(GL::SamplerFilter::Linear) #else
.setMagnificationFilter(GL::SamplerFilter::Linear) return {};
.setStorage(1, internalFormat, size); #endif
/* 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>{}});
}
std::vector<Range2Di> GlyphCache::reserve(const std::vector<Vector2i>& sizes) {
CORRADE_ASSERT((glyphs.size() == 1 && glyphs.at(0) == std::pair<Vector2i, Range2Di>()),
"Text::GlyphCache::reserve(): reserving space in non-empty cache is not yet implemented", {});
glyphs.reserve(glyphs.size() + sizes.size());
return TextureTools::atlas(_size, sizes, _padding);
}
void GlyphCache::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 GlyphCache::setImage(const Vector2i& offset, const ImageView2D& image) { void GlyphCache::doSetImage(const Vector2i& offset, const ImageView2D& image) {
/** @todo some internalformat/format checking also here (if querying internal format is not slow) */ /** @todo some internalformat/format checking also here (if querying internal format is not slow) */
_texture.setSubImage(0, offset, image); _texture.setSubImage(0, offset, image);
} }
#ifndef MAGNUM_TARGET_GLES
Image2D GlyphCache::doImage() { return _texture.image(0, PixelFormat::R8Unorm); }
#endif
}} }}

115
src/Magnum/Text/GlyphCache.h

@ -29,12 +29,11 @@
* @brief Class @ref Magnum::Text::GlyphCache * @brief Class @ref Magnum::Text::GlyphCache
*/ */
#include <vector> #include "Magnum/configure.h"
#include <unordered_map>
#include "Magnum/Math/Range.h" #ifdef MAGNUM_TARGET_GL
#include "Magnum/GL/Texture.h" #include "Magnum/GL/Texture.h"
#include "Magnum/Text/visibility.h" #include "Magnum/Text/AbstractGlyphCache.h"
namespace Magnum { namespace Text { namespace Magnum { namespace Text {
@ -51,11 +50,20 @@ Create GlyphCache object with sufficient size and then call
@snippet MagnumText.cpp GlyphCache-usage @snippet MagnumText.cpp GlyphCache-usage
See @ref Renderer for information about text rendering. See @ref Renderer for information about text rendering.
This class supports the @ref GlyphCacheFeature::ImageDownload (and thus calling
@ref image()) only on desktop OpenGL, due to using @ref GL::Texture::image(),
which is not available on @ref CORRADE_TARGET_GLES "OpenGL ES" platforms.
@todo Some way for Font to negotiate or check internal texture format @todo Some way for Font to negotiate or check internal texture format
@todo Default glyph 0 with rect 0 0 0 0 will result in negative dimensions when @todo Default glyph 0 with rect 0 0 0 0 will result in negative dimensions when
nonzero padding is removed nonzero padding is removed
@note This class is available only if Magnum is compiled with
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features
for more information.
*/ */
class MAGNUM_TEXT_EXPORT GlyphCache { class MAGNUM_TEXT_EXPORT GlyphCache: public AbstractGlyphCache {
public: public:
/** /**
* @brief Constructor * @brief Constructor
@ -98,103 +106,24 @@ class MAGNUM_TEXT_EXPORT GlyphCache {
*/ */
explicit GlyphCache(const Vector2i& size, const Vector2i& padding = {}); explicit GlyphCache(const Vector2i& size, const Vector2i& padding = {});
virtual ~GlyphCache(); ~GlyphCache();
/**
* @brief Cache size
*
* Size of unscaled glyph cache texture.
*/
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 Cache texture */ /** @brief Cache texture */
GL::Texture2D& texture() { return _texture; } GL::Texture2D& texture() { return _texture; }
/**
* @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.
*/
virtual void setImage(const Vector2i& offset, const ImageView2D& image);
private: private:
void MAGNUM_LOCAL initialize(GL::TextureFormat internalFormat, const Vector2i& size); GlyphCacheFeatures MAGNUM_LOCAL doFeatures() const override;
void MAGNUM_LOCAL doSetImage(const Vector2i& offset, const ImageView2D& image) override;
#ifndef MAGNUM_TARGET_GLES
Image2D MAGNUM_LOCAL doImage() override;
#endif
Vector2i _size, _padding;
GL::Texture2D _texture; GL::Texture2D _texture;
std::unordered_map<UnsignedInt, std::pair<Vector2i, Range2Di>> glyphs;
}; };
}} }}
#else
#error this header is available only in the OpenGL build
#endif
#endif #endif

1
src/Magnum/Text/Renderer.cpp

@ -34,6 +34,7 @@
#include "Magnum/Math/Functions.h" #include "Magnum/Math/Functions.h"
#include "Magnum/Shaders/AbstractVector.h" #include "Magnum/Shaders/AbstractVector.h"
#include "Magnum/Text/AbstractFont.h" #include "Magnum/Text/AbstractFont.h"
#include "Magnum/Text/GlyphCache.h"
namespace Magnum { namespace Text { namespace Magnum { namespace Text {

6
src/Magnum/Text/Renderer.h

@ -29,6 +29,9 @@
* @brief Class @ref Magnum::Text::AbstractRenderer, @ref Magnum::Text::Renderer, typedef @ref Magnum::Text::Renderer2D, @ref Magnum::Text::Renderer3D * @brief Class @ref Magnum::Text::AbstractRenderer, @ref Magnum::Text::Renderer, typedef @ref Magnum::Text::Renderer2D, @ref Magnum::Text::Renderer3D
*/ */
#include "Magnum/configure.h"
#ifdef MAGNUM_TARGET_GL
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@ -241,5 +244,8 @@ typedef Renderer<2> Renderer2D;
typedef Renderer<3> Renderer3D; typedef Renderer<3> Renderer3D;
}} }}
#else
#error this header is available only in the OpenGL build
#endif
#endif #endif

75
src/Magnum/Text/Test/AbstractFontConverterTest.cpp

@ -29,8 +29,9 @@
#include <Corrade/TestSuite/Compare/Container.h> #include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include "Magnum/Text/AbstractFont.h"
#include "Magnum/Text/AbstractFontConverter.h" #include "Magnum/Text/AbstractFontConverter.h"
#include "Magnum/Text/GlyphCache.h" #include "Magnum/Text/AbstractGlyphCache.h"
#include "configure.h" #include "configure.h"
@ -67,10 +68,24 @@ AbstractFontConverterTest::AbstractFontConverterTest() {
Utility::Directory::mkpath(TEXT_TEST_OUTPUT_DIR); Utility::Directory::mkpath(TEXT_TEST_OUTPUT_DIR);
} }
/* *static_cast<GlyphCache*>(nullptr) makes Clang Analyzer grumpy */ struct DummyFont: AbstractFont {
char nullData; Features doFeatures() const override { return {}; }
AbstractFont& nullFont = *reinterpret_cast<AbstractFont*>(nullData); bool doIsOpened() const override { return false; }
GlyphCache& nullGlyphCache = *reinterpret_cast<GlyphCache*>(nullData); void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} dummyFont;
struct DummyGlyphCache: AbstractGlyphCache {
using AbstractGlyphCache::AbstractGlyphCache;
GlyphCacheFeatures doFeatures() const override { return {}; }
void doSetImage(const Vector2i&, const ImageView2D&) override {}
} dummyGlyphCache{{}};
void AbstractFontConverterTest::convertGlyphs() { void AbstractFontConverterTest::convertGlyphs() {
class GlyphExporter: public AbstractFontConverter { class GlyphExporter: public AbstractFontConverter {
@ -81,7 +96,7 @@ void AbstractFontConverterTest::convertGlyphs() {
private: private:
Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont; } Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont; }
Containers::Array<char> doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string& characters) const override { Containers::Array<char> doExportFontToSingleData(AbstractFont&, AbstractGlyphCache&, const std::u32string& characters) const override {
_characters = characters; _characters = characters;
return nullptr; return nullptr;
} }
@ -91,7 +106,7 @@ void AbstractFontConverterTest::convertGlyphs() {
std::u32string characters; std::u32string characters;
GlyphExporter exporter(characters); GlyphExporter exporter(characters);
exporter.exportFontToSingleData(nullFont, nullGlyphCache, "abC01a0 "); exporter.exportFontToSingleData(dummyFont, dummyGlyphCache, "abC01a0 ");
CORRADE_COMPARE(characters, U" 01Cab"); CORRADE_COMPARE(characters, U" 01Cab");
} }
@ -100,7 +115,7 @@ void AbstractFontConverterTest::exportFontToSingleData() {
private: private:
Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont; } Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont; }
Containers::Array<char> doExportFontToSingleData(AbstractFont&, GlyphCache&, const std::u32string&) const override { Containers::Array<char> doExportFontToSingleData(AbstractFont&, AbstractGlyphCache&, const std::u32string&) const override {
Containers::Array<char> data(1); Containers::Array<char> data(1);
data[0] = '\xee'; data[0] = '\xee';
return data; return data;
@ -109,7 +124,7 @@ void AbstractFontConverterTest::exportFontToSingleData() {
/* doExportFontToData() should call doExportFontToSingleData() */ /* doExportFontToData() should call doExportFontToSingleData() */
SingleDataExporter exporter; SingleDataExporter exporter;
auto ret = exporter.exportFontToData(nullFont, nullGlyphCache, "font.out", {}); auto ret = exporter.exportFontToData(dummyFont, dummyGlyphCache, "font.out", {});
CORRADE_COMPARE(ret.size(), 1); CORRADE_COMPARE(ret.size(), 1);
CORRADE_COMPARE(ret[0].first, "font.out"); CORRADE_COMPARE(ret[0].first, "font.out");
CORRADE_COMPARE(ret[0].second.size(), 1); CORRADE_COMPARE(ret[0].second.size(), 1);
@ -121,7 +136,7 @@ void AbstractFontConverterTest::exportFontToFile() {
private: private:
Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont|Feature::MultiFile; } Features doFeatures() const override { return Feature::ConvertData|Feature::ExportFont|Feature::MultiFile; }
std::vector<std::pair<std::string, Containers::Array<char>>> doExportFontToData(AbstractFont&, GlyphCache&, const std::string& filename, const std::u32string&) const override { std::vector<std::pair<std::string, Containers::Array<char>>> doExportFontToData(AbstractFont&, AbstractGlyphCache&, const std::string& filename, const std::u32string&) const override {
/* Why the hell GCC 4.9 fails to do proper move so I need to /* Why the hell GCC 4.9 fails to do proper move so I need to
work around that this ugly way?! */ work around that this ugly way?! */
std::vector<std::pair<std::string, Containers::Array<char>>> ret; std::vector<std::pair<std::string, Containers::Array<char>>> ret;
@ -137,7 +152,7 @@ void AbstractFontConverterTest::exportFontToFile() {
/* doExportToFile() should call doExportToData() */ /* doExportToFile() should call doExportToData() */
DataExporter exporter; DataExporter exporter;
bool exported = exporter.exportFontToFile(nullFont, nullGlyphCache, Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "font.out"), {}); bool exported = exporter.exportFontToFile(dummyFont, dummyGlyphCache, Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "font.out"), {});
CORRADE_VERIFY(exported); CORRADE_VERIFY(exported);
CORRADE_COMPARE_AS(Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "font.out"), CORRADE_COMPARE_AS(Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "font.out"),
"\xf0", TestSuite::Compare::FileToString); "\xf0", TestSuite::Compare::FileToString);
@ -146,18 +161,16 @@ void AbstractFontConverterTest::exportFontToFile() {
} }
void AbstractFontConverterTest::exportGlyphCacheToSingleData() { void AbstractFontConverterTest::exportGlyphCacheToSingleData() {
class SingleDataExporter: public Text::AbstractFontConverter { struct: Text::AbstractFontConverter {
private: Features doFeatures() const override { return Feature::ConvertData|Feature::ExportGlyphCache; }
Features doFeatures() const override { return Feature::ConvertData|Feature::ExportGlyphCache; }
Containers::Array<char> doExportGlyphCacheToSingleData(GlyphCache&) const override { Containers::Array<char> doExportGlyphCacheToSingleData(AbstractGlyphCache&) const override {
return Containers::Array<char>{Containers::InPlaceInit, {'\xee'}}; return Containers::Array<char>{Containers::InPlaceInit, {'\xee'}};
} }
}; } exporter;
/* doExportGlyphCacheToData() should call doExportGlyphCacheToSingleData() */ /* doExportGlyphCacheToData() should call doExportGlyphCacheToSingleData() */
SingleDataExporter exporter; auto ret = exporter.exportGlyphCacheToData(dummyGlyphCache, "font.out");
auto ret = exporter.exportGlyphCacheToData(nullGlyphCache, "font.out");
CORRADE_COMPARE(ret.size(), 1); CORRADE_COMPARE(ret.size(), 1);
CORRADE_COMPARE(ret[0].first, "font.out"); CORRADE_COMPARE(ret[0].first, "font.out");
CORRADE_COMPARE_AS(ret[0].second, CORRADE_COMPARE_AS(ret[0].second,
@ -170,7 +183,7 @@ void AbstractFontConverterTest::exportGlyphCacheToFile() {
private: private:
Features doFeatures() const override { return Feature::ConvertData|Feature::ExportGlyphCache|Feature::MultiFile; } Features doFeatures() const override { return Feature::ConvertData|Feature::ExportGlyphCache|Feature::MultiFile; }
std::vector<std::pair<std::string, Containers::Array<char>>> doExportGlyphCacheToData(GlyphCache&, const std::string& filename) const override { std::vector<std::pair<std::string, Containers::Array<char>>> doExportGlyphCacheToData(AbstractGlyphCache&, const std::string& filename) const override {
/* Why the hell GCC 4.9 fails to do proper move so I need to /* Why the hell GCC 4.9 fails to do proper move so I need to
work around that this ugly way?! */ work around that this ugly way?! */
std::vector<std::pair<std::string, Containers::Array<char>>> ret; std::vector<std::pair<std::string, Containers::Array<char>>> ret;
@ -186,7 +199,7 @@ void AbstractFontConverterTest::exportGlyphCacheToFile() {
/* doExportGlyphCacheToFile() should call doExportGlyphCacheToData() */ /* doExportGlyphCacheToFile() should call doExportGlyphCacheToData() */
DataExporter exporter; DataExporter exporter;
bool exported = exporter.exportGlyphCacheToFile(nullGlyphCache, Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "glyphcache.out")); bool exported = exporter.exportGlyphCacheToFile(dummyGlyphCache, Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "glyphcache.out"));
CORRADE_VERIFY(exported); CORRADE_VERIFY(exported);
CORRADE_COMPARE_AS(Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "glyphcache.out"), CORRADE_COMPARE_AS(Utility::Directory::join(TEXT_TEST_OUTPUT_DIR, "glyphcache.out"),
"\xf0", TestSuite::Compare::FileToString); "\xf0", TestSuite::Compare::FileToString);
@ -198,9 +211,9 @@ class SingleGlyphCacheDataImporter: public Text::AbstractFontConverter {
private: private:
Features doFeatures() const override { return Feature::ConvertData|Feature::ImportGlyphCache; } Features doFeatures() const override { return Feature::ConvertData|Feature::ImportGlyphCache; }
Containers::Pointer<GlyphCache> doImportGlyphCacheFromSingleData(const Containers::ArrayView<const char> data) const override { Containers::Pointer<AbstractGlyphCache> doImportGlyphCacheFromSingleData(const Containers::ArrayView<const char> data) const override {
if(data.size() == 1 && data[0] == '\xa5') if(data.size() == 1 && data[0] == '\xa5')
return Containers::Pointer<GlyphCache>(reinterpret_cast<GlyphCache*>(0xdeadbeef)); return Containers::pointer(new DummyGlyphCache{{123, 345}});
return nullptr; return nullptr;
} }
}; };
@ -209,21 +222,15 @@ void AbstractFontConverterTest::importGlyphCacheFromSingleData() {
/* doImportFromData() should call doImportFromSingleData() */ /* doImportFromData() should call doImportFromSingleData() */
SingleGlyphCacheDataImporter importer; SingleGlyphCacheDataImporter importer;
const char data[] = {'\xa5'}; const char data[] = {'\xa5'};
Containers::Pointer<GlyphCache> cache = importer.importGlyphCacheFromData({{{}, data}}); Containers::Pointer<AbstractGlyphCache> cache = importer.importGlyphCacheFromData({{{}, data}});
CORRADE_COMPARE(cache.get(), reinterpret_cast<GlyphCache*>(0xdeadbeef)); CORRADE_COMPARE(cache->textureSize(), (Vector2i{123, 345}));
/* The pointer is invalid, avoid deletion */
cache.release();
} }
void AbstractFontConverterTest::importGlyphCacheFromFile() { void AbstractFontConverterTest::importGlyphCacheFromFile() {
/* doImportFromFile() should call doImportFromSingleData() */ /* doImportFromFile() should call doImportFromSingleData() */
SingleGlyphCacheDataImporter importer; SingleGlyphCacheDataImporter importer;
Containers::Pointer<GlyphCache> cache = importer.importGlyphCacheFromFile(Utility::Directory::join(TEXT_TEST_DIR, "data.bin")); Containers::Pointer<AbstractGlyphCache> cache = importer.importGlyphCacheFromFile(Utility::Directory::join(TEXT_TEST_DIR, "data.bin"));
CORRADE_COMPARE(cache.get(), reinterpret_cast<GlyphCache*>(0xdeadbeef)); CORRADE_COMPARE(cache->textureSize(), (Vector2i{123, 345}));
/* The pointer is invalid, avoid deletion */
cache.release();
} }
}}}} }}}}

418
src/Magnum/Text/Test/AbstractFontTest.cpp

@ -23,12 +23,14 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <sstream>
#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/ArrayView.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include "Magnum/Math/Vector2.h" #include "Magnum/Math/Vector2.h"
#include "Magnum/Text/AbstractFont.h" #include "Magnum/Text/AbstractFont.h"
#include "Magnum/Text/AbstractGlyphCache.h"
#include "configure.h" #include "configure.h"
@ -38,12 +40,62 @@ struct AbstractFontTest: TestSuite::Tester {
explicit AbstractFontTest(); explicit AbstractFontTest();
void openSingleData(); void openSingleData();
void openFile();
void openFileAsData();
void openFileAsDataNotFound();
void openFileNotImplemented();
void openDataNotSupported();
void openDataNotImplemented();
void glyphId();
void glyphIdNoFont();
void glyphAdvance();
void glyphAdvanceNoFont();
void layout();
void layoutNoFont();
void fillGlyphCache();
void fillGlyphCacheNotSupported();
void fillGlyphCacheNotImplemented();
void fillGlyphCacheNoFont();
void createGlyphCache();
void createGlyphCacheNotSupported();
void createGlyphCacheNotImplemented();
void createGlyphCacheNoFont();
}; };
AbstractFontTest::AbstractFontTest() { AbstractFontTest::AbstractFontTest() {
addTests({&AbstractFontTest::openSingleData, addTests({&AbstractFontTest::openSingleData,
&AbstractFontTest::openFile});
&AbstractFontTest::openFileAsData,
&AbstractFontTest::openFileAsDataNotFound,
&AbstractFontTest::openFileNotImplemented,
&AbstractFontTest::openDataNotSupported,
&AbstractFontTest::openDataNotImplemented,
&AbstractFontTest::glyphId,
&AbstractFontTest::glyphIdNoFont,
&AbstractFontTest::glyphAdvance,
&AbstractFontTest::glyphAdvanceNoFont,
&AbstractFontTest::layout,
&AbstractFontTest::layoutNoFont,
&AbstractFontTest::fillGlyphCache,
&AbstractFontTest::fillGlyphCacheNotSupported,
&AbstractFontTest::fillGlyphCacheNotImplemented,
&AbstractFontTest::fillGlyphCacheNoFont,
&AbstractFontTest::createGlyphCache,
&AbstractFontTest::createGlyphCacheNotSupported,
&AbstractFontTest::createGlyphCacheNotImplemented,
&AbstractFontTest::createGlyphCacheNoFont});
} }
class SingleDataFont: public Text::AbstractFont { class SingleDataFont: public Text::AbstractFont {
@ -63,7 +115,7 @@ class SingleDataFont: public Text::AbstractFont {
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; } Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const GlyphCache&, Float, const std::string&) override { Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr; return nullptr;
} }
@ -79,7 +131,7 @@ void AbstractFontTest::openSingleData() {
CORRADE_VERIFY(font.isOpened()); CORRADE_VERIFY(font.isOpened());
} }
void AbstractFontTest::openFile() { void AbstractFontTest::openFileAsData() {
/* doOpenFile() should call doOpenSingleData() */ /* doOpenFile() should call doOpenSingleData() */
SingleDataFont font; SingleDataFont font;
CORRADE_VERIFY(!font.isOpened()); CORRADE_VERIFY(!font.isOpened());
@ -87,6 +139,364 @@ void AbstractFontTest::openFile() {
CORRADE_VERIFY(font.isOpened()); CORRADE_VERIFY(font.isOpened());
} }
void AbstractFontTest::openFileAsDataNotFound() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return Feature::OpenData; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!font.openFile("nonexistent.foo", 12.0f));
CORRADE_COMPARE(out.str(), "Text::AbstractFont::openFile(): cannot open file nonexistent.foo\n");
}
void AbstractFontTest::openFileNotImplemented() {
struct MyFont: AbstractFont {
/* Supports neither file nor data opening */
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
std::ostringstream out;
Error redirectError{&out};
font.openFile("file.foo", 34.0f);
CORRADE_COMPARE(out.str(), "Text::AbstractFont::openFile(): not implemented\n");
}
void AbstractFontTest::openDataNotSupported() {
struct MyFont: AbstractFont {
/* Supports neither file nor data opening */
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
std::ostringstream out;
Error redirectError{&out};
/** @todo replace this with nullptr once multi-file support is done
properly via callbacks */
font.openData({}, 34.0f);
CORRADE_COMPARE(out.str(), "Text::AbstractFont::openData(): feature not supported\n");
}
void AbstractFontTest::openDataNotImplemented() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return Feature::OpenData; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
std::ostringstream out;
Error redirectError{&out};
/** @todo replace this with nullptr and openSingleData() once multi-file
support is done properly via callbacks */
font.openData({{}}, 34.0f);
CORRADE_COMPARE(out.str(), "Text::AbstractFont::openSingleData(): feature advertised but not implemented\n");
}
void AbstractFontTest::glyphId() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t a) override { return a*10; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
CORRADE_COMPARE(font.glyphId(U'a'), 970);
}
void AbstractFontTest::glyphIdNoFont() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
std::ostringstream out;
Error redirectError{&out};
font.glyphId('a');
CORRADE_COMPARE(out.str(), "Text::AbstractFont::glyphId(): no font opened\n");
}
void AbstractFontTest::glyphAdvance() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt a) override { return {a*10.0f, -Float(a)/10.0f}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
CORRADE_COMPARE(font.glyphAdvance(97), (Vector2{970.0f, -9.7f}));
}
void AbstractFontTest::glyphAdvanceNoFont() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override {
return nullptr;
}
} font;
std::ostringstream out;
Error redirectError{&out};
font.glyphAdvance(97);
CORRADE_COMPARE(out.str(), "Text::AbstractFont::glyphAdvance(): no font opened\n");
}
struct DummyGlyphCache: AbstractGlyphCache {
using AbstractGlyphCache::AbstractGlyphCache;
GlyphCacheFeatures doFeatures() const override { return {}; }
void doSetImage(const Vector2i&, const ImageView2D&) override {}
};
void AbstractFontTest::layout() {
struct Layouter: AbstractLayouter {
explicit Layouter(UnsignedInt count): AbstractLayouter{count} {}
std::tuple<Range2D, Range2D, Vector2> doRenderGlyph(UnsignedInt) override { return {}; }
};
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache& cache, Float size, const std::string& str) override {
return Containers::pointer<Layouter>(UnsignedInt(cache.textureSize().x()*str.size()*size));
}
} font;
DummyGlyphCache cache{{100, 200}};
Containers::Pointer<AbstractLayouter> layouter = font.layout(cache, 0.25f, "hello");
CORRADE_COMPARE(layouter->glyphCount(), 100*5/4);
}
void AbstractFontTest::layoutNoFont() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
DummyGlyphCache cache{{100, 200}};
font.layout(cache, 0.25f, "hello");
CORRADE_COMPARE(out.str(), "Text::AbstractFont::layout(): no font opened\n");
}
void AbstractFontTest::fillGlyphCache() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
void doFillGlyphCache(AbstractGlyphCache& cache, const std::u32string& characters) override {
for(char a: characters) cache.insert(a*10, {a/2, a*2}, {});
}
} font;
DummyGlyphCache cache{{100, 100}};
CORRADE_COMPARE(cache.glyphCount(), 1);
font.fillGlyphCache(cache, "helo");
CORRADE_COMPARE(cache.glyphCount(), 5);
CORRADE_COMPARE(cache['h'*10], (std::pair<Vector2i, Range2Di>{{52, 208}, {}}));
CORRADE_COMPARE(cache['e'*10], (std::pair<Vector2i, Range2Di>{{50, 202}, {}}));
CORRADE_COMPARE(cache['l'*10], (std::pair<Vector2i, Range2Di>{{54, 216}, {}}));
CORRADE_COMPARE(cache['o'*10], (std::pair<Vector2i, Range2Di>{{55, 222}, {}}));
}
void AbstractFontTest::fillGlyphCacheNotSupported() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return Feature::PreparedGlyphCache; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
DummyGlyphCache cache{{100, 100}};
font.fillGlyphCache(cache, "hello");
CORRADE_COMPARE(out.str(), "Text::AbstractFont::fillGlyphCache(): feature not supported\n");
}
void AbstractFontTest::fillGlyphCacheNotImplemented() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
DummyGlyphCache cache{{100, 100}};
font.fillGlyphCache(cache, "hello");
CORRADE_COMPARE(out.str(), "Text::AbstractFont::fillGlyphCache(): feature advertised but not implemented\n");
}
void AbstractFontTest::fillGlyphCacheNoFont() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
DummyGlyphCache cache{{100, 100}};
font.fillGlyphCache(cache, "hello");
CORRADE_COMPARE(out.str(), "Text::AbstractFont::fillGlyphCache(): no font opened\n");
}
void AbstractFontTest::createGlyphCache() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return Feature::PreparedGlyphCache; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
Containers::Pointer<AbstractGlyphCache> doCreateGlyphCache() override {
Containers::Pointer<AbstractGlyphCache> cache{new DummyGlyphCache{{100, 100}}};
for(char a: std::string{"helo"}) cache->insert(a*10, {a/2, a*2}, {});
return cache;
}
} font;
Containers::Pointer<AbstractGlyphCache> cache = font.createGlyphCache();
CORRADE_COMPARE(cache->glyphCount(), 5);
CORRADE_COMPARE((*cache)['h'*10], (std::pair<Vector2i, Range2Di>{{52, 208}, {}}));
CORRADE_COMPARE((*cache)['e'*10], (std::pair<Vector2i, Range2Di>{{50, 202}, {}}));
CORRADE_COMPARE((*cache)['l'*10], (std::pair<Vector2i, Range2Di>{{54, 216}, {}}));
CORRADE_COMPARE((*cache)['o'*10], (std::pair<Vector2i, Range2Di>{{55, 222}, {}}));
}
void AbstractFontTest::createGlyphCacheNotSupported() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return {}; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
font.createGlyphCache();
CORRADE_COMPARE(out.str(), "Text::AbstractFont::createGlyphCache(): feature not supported\n");
}
void AbstractFontTest::createGlyphCacheNotImplemented() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return Feature::PreparedGlyphCache; }
bool doIsOpened() const override { return true; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
font.createGlyphCache();
CORRADE_COMPARE(out.str(), "Text::AbstractFont::createGlyphCache(): feature advertised but not implemented\n");
}
void AbstractFontTest::createGlyphCacheNoFont() {
struct MyFont: AbstractFont {
Features doFeatures() const override { return Feature::PreparedGlyphCache; }
bool doIsOpened() const override { return false; }
void doClose() override {}
UnsignedInt doGlyphId(char32_t) override { return {}; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) override { return nullptr; }
} font;
std::ostringstream out;
Error redirectError{&out};
font.createGlyphCache();
CORRADE_COMPARE(out.str(), "Text::AbstractFont::createGlyphCache(): no font opened\n");
}
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Text::Test::AbstractFontTest) CORRADE_TEST_MAIN(Magnum::Text::Test::AbstractFontTest)

192
src/Magnum/Text/Test/AbstractGlyphCacheTest.cpp

@ -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)

7
src/Magnum/Text/Test/CMakeLists.txt

@ -35,27 +35,30 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h) ${CMAKE_CURRENT_BINARY_DIR}/configure.h)
corrade_add_test(TextAbstractFontTest AbstractFontTest.cpp corrade_add_test(TextAbstractFontTest AbstractFontTest.cpp
LIBRARIES Magnum MagnumText LIBRARIES Magnum MagnumTextTestLib
FILES data.bin) FILES data.bin)
target_include_directories(TextAbstractFontTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(TextAbstractFontTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
corrade_add_test(TextAbstractFontConverterTest AbstractFontConverterTest.cpp corrade_add_test(TextAbstractFontConverterTest AbstractFontConverterTest.cpp
LIBRARIES Magnum MagnumText LIBRARIES Magnum MagnumText
FILES data.bin) FILES data.bin)
target_include_directories(TextAbstractFontConverterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(TextAbstractFontConverterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
corrade_add_test(TextAbstractGlyphCacheTest AbstractGlyphCacheTest.cpp LIBRARIES MagnumTextTestLib)
corrade_add_test(TextAbstractLayouterTest AbstractLayouterTest.cpp LIBRARIES Magnum MagnumText) corrade_add_test(TextAbstractLayouterTest AbstractLayouterTest.cpp LIBRARIES Magnum MagnumText)
set_target_properties( set_target_properties(
TextAbstractFontTest TextAbstractFontTest
TextAbstractFontConverterTest TextAbstractFontConverterTest
TextAbstractGlyphCacheTest
TextAbstractLayouterTest TextAbstractLayouterTest
PROPERTIES FOLDER "Magnum/Text/Test") PROPERTIES FOLDER "Magnum/Text/Test")
if(BUILD_GL_TESTS) if(TARGET_GL AND BUILD_GL_TESTS)
corrade_add_test(TextDistanceFieldGlyphCacheGLTest DistanceFieldGlyphCacheGLTest.cpp LIBRARIES MagnumText MagnumOpenGLTester) corrade_add_test(TextDistanceFieldGlyphCacheGLTest DistanceFieldGlyphCacheGLTest.cpp LIBRARIES MagnumText MagnumOpenGLTester)
corrade_add_test(TextGlyphCacheGLTest GlyphCacheGLTest.cpp LIBRARIES MagnumText MagnumOpenGLTester) corrade_add_test(TextGlyphCacheGLTest GlyphCacheGLTest.cpp LIBRARIES MagnumText MagnumOpenGLTester)
corrade_add_test(TextRendererGLTest RendererGLTest.cpp LIBRARIES MagnumText MagnumOpenGLTester) corrade_add_test(TextRendererGLTest RendererGLTest.cpp LIBRARIES MagnumText MagnumOpenGLTester)
set_target_properties( set_target_properties(
TextDistanceFieldGlyphCacheGLTest
TextGlyphCacheGLTest TextGlyphCacheGLTest
TextRendererGLTest TextRendererGLTest
PROPERTIES FOLDER "Magnum/Text/Test") PROPERTIES FOLDER "Magnum/Text/Test")

44
src/Magnum/Text/Test/GlyphCacheGLTest.cpp

@ -34,14 +34,10 @@ struct GlyphCacheGLTest: GL::OpenGLTester {
explicit GlyphCacheGLTest(); explicit GlyphCacheGLTest();
void initialize(); void initialize();
void access();
void reserve();
}; };
GlyphCacheGLTest::GlyphCacheGLTest() { GlyphCacheGLTest::GlyphCacheGLTest() {
addTests({&GlyphCacheGLTest::initialize, addTests({&GlyphCacheGLTest::initialize});
&GlyphCacheGLTest::access,
&GlyphCacheGLTest::reserve});
} }
void GlyphCacheGLTest::initialize() { void GlyphCacheGLTest::initialize() {
@ -53,44 +49,6 @@ void GlyphCacheGLTest::initialize() {
#endif #endif
} }
void GlyphCacheGLTest::access() {
Text::GlyphCache 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 "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 GlyphCacheGLTest::reserve() {
Text::GlyphCache cache(Vector2i(236));
/* Verify that this works for "empty" cache */
CORRADE_VERIFY(!cache.reserve({{5, 3}}).empty());
}
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Text::Test::GlyphCacheGLTest) CORRADE_TEST_MAIN(Magnum::Text::Test::GlyphCacheGLTest)

4
src/Magnum/Text/Test/RendererGLTest.cpp

@ -79,7 +79,7 @@ class TestFont: public Text::AbstractFont {
UnsignedInt doGlyphId(char32_t) override { return 0; } UnsignedInt doGlyphId(char32_t) override { return 0; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; } Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const GlyphCache&, const Float size, const std::string& text) override { Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, const Float size, const std::string& text) override {
return Containers::Pointer<AbstractLayouter>(new TestLayouter(size, text.size())); return Containers::Pointer<AbstractLayouter>(new TestLayouter(size, text.size()));
} }
}; };
@ -353,7 +353,7 @@ void RendererGLTest::multiline() {
UnsignedInt doGlyphId(char32_t) override { return 0; } UnsignedInt doGlyphId(char32_t) override { return 0; }
Vector2 doGlyphAdvance(UnsignedInt) override { return {}; } Vector2 doGlyphAdvance(UnsignedInt) override { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const GlyphCache&, Float, const std::string& text) override { Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string& text) override {
return Containers::Pointer<AbstractLayouter>(new Layouter(text.size())); return Containers::Pointer<AbstractLayouter>(new Layouter(text.size()));
} }

8
src/Magnum/Text/Text.h

@ -37,17 +37,21 @@ namespace Magnum { namespace Text {
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
class AbstractFont; class AbstractFont;
class AbstractFontConverter; class AbstractFontConverter;
class AbstractGlyphCache;
class AbstractLayouter; class AbstractLayouter;
class DistanceFieldGlyphCache;
class GlyphCache;
enum class Alignment: UnsignedByte; enum class Alignment: UnsignedByte;
class AbstractGlyphCache;
#ifdef MAGNUM_TARGET_GL
class DistanceFieldGlyphCache;
class GlyphCache;
class AbstractRenderer; class AbstractRenderer;
template<UnsignedInt> class Renderer; template<UnsignedInt> class Renderer;
typedef Renderer<2> Renderer2D; typedef Renderer<2> Renderer2D;
typedef Renderer<3> Renderer3D; typedef Renderer<3> Renderer3D;
#endif #endif
#endif
}} }}

2
src/Magnum/Text/visibility.h

@ -31,7 +31,7 @@
#ifndef DOXYGEN_GENERATING_OUTPUT #ifndef DOXYGEN_GENERATING_OUTPUT
#ifndef MAGNUM_BUILD_STATIC #ifndef MAGNUM_BUILD_STATIC
#ifdef MagnumText_EXPORTS #if defined(MagnumText_EXPORTS) || defined(MagnumTextObjects_EXPORTS)
#define MAGNUM_TEXT_EXPORT CORRADE_VISIBILITY_EXPORT #define MAGNUM_TEXT_EXPORT CORRADE_VISIBILITY_EXPORT
#else #else
#define MAGNUM_TEXT_EXPORT CORRADE_VISIBILITY_IMPORT #define MAGNUM_TEXT_EXPORT CORRADE_VISIBILITY_IMPORT

2
src/MagnumPlugins/MagnumFont/CMakeLists.txt

@ -56,7 +56,7 @@ if(BUILD_PLUGINS_STATIC)
target_sources(MagnumFont INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/importStaticPlugin.cpp) target_sources(MagnumFont INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/importStaticPlugin.cpp)
endif() endif()
if(BUILD_GL_TESTS) if(BUILD_TESTS)
add_subdirectory(Test) add_subdirectory(Test)
endif() endif()

14
src/MagnumPlugins/MagnumFont/MagnumFont.cpp

@ -48,13 +48,13 @@ struct MagnumFont::Data {
namespace { namespace {
class MagnumFontLayouter: public AbstractLayouter { class MagnumFontLayouter: public AbstractLayouter {
public: public:
explicit MagnumFontLayouter(const std::vector<Vector2>& glyphAdvance, const GlyphCache& cache, Float fontSize, Float textSize, std::vector<UnsignedInt>&& glyphs); explicit MagnumFontLayouter(const std::vector<Vector2>& glyphAdvance, const AbstractGlyphCache& cache, Float fontSize, Float textSize, std::vector<UnsignedInt>&& glyphs);
private: private:
std::tuple<Range2D, Range2D, Vector2> doRenderGlyph(UnsignedInt i) override; std::tuple<Range2D, Range2D, Vector2> doRenderGlyph(UnsignedInt i) override;
const std::vector<Vector2>& glyphAdvance; const std::vector<Vector2>& glyphAdvance;
const GlyphCache& cache; const AbstractGlyphCache& cache;
const Float fontSize, textSize; const Float fontSize, textSize;
const std::vector<UnsignedInt> glyphs; const std::vector<UnsignedInt> glyphs;
}; };
@ -184,9 +184,9 @@ Vector2 MagnumFont::doGlyphAdvance(const UnsignedInt glyph) {
return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2(); return glyph < _opened->glyphAdvance.size() ? _opened->glyphAdvance[glyph] : Vector2();
} }
Containers::Pointer<GlyphCache> MagnumFont::doCreateGlyphCache() { Containers::Pointer<AbstractGlyphCache> MagnumFont::doCreateGlyphCache() {
/* Set cache image */ /* Set cache image */
Containers::Pointer<GlyphCache> cache(new Text::GlyphCache( Containers::Pointer<AbstractGlyphCache> cache(new Text::GlyphCache(
_opened->conf.value<Vector2i>("originalImageSize"), _opened->conf.value<Vector2i>("originalImageSize"),
_opened->image.size(), _opened->image.size(),
_opened->conf.value<Vector2i>("padding"))); _opened->conf.value<Vector2i>("padding")));
@ -200,7 +200,7 @@ Containers::Pointer<GlyphCache> MagnumFont::doCreateGlyphCache() {
return cache; return cache;
} }
Containers::Pointer<AbstractLayouter> MagnumFont::doLayout(const GlyphCache& cache, Float size, const std::string& text) { Containers::Pointer<AbstractLayouter> MagnumFont::doLayout(const AbstractGlyphCache& cache, Float size, const std::string& text) {
/* Get glyph codes from characters */ /* Get glyph codes from characters */
std::vector<UnsignedInt> glyphs; std::vector<UnsignedInt> glyphs;
glyphs.reserve(text.size()); glyphs.reserve(text.size());
@ -216,7 +216,7 @@ Containers::Pointer<AbstractLayouter> MagnumFont::doLayout(const GlyphCache& cac
namespace { namespace {
MagnumFontLayouter::MagnumFontLayouter(const std::vector<Vector2>& glyphAdvance, const GlyphCache& cache, const Float fontSize, const Float textSize, std::vector<UnsignedInt>&& glyphs): AbstractLayouter(glyphs.size()), glyphAdvance(glyphAdvance), cache(cache), fontSize(fontSize), textSize(textSize), glyphs(std::move(glyphs)) {} MagnumFontLayouter::MagnumFontLayouter(const std::vector<Vector2>& glyphAdvance, const AbstractGlyphCache& cache, const Float fontSize, const Float textSize, std::vector<UnsignedInt>&& glyphs): AbstractLayouter(glyphs.size()), glyphAdvance(glyphAdvance), cache(cache), fontSize(fontSize), textSize(textSize), glyphs(std::move(glyphs)) {}
std::tuple<Range2D, Range2D, Vector2> MagnumFontLayouter::doRenderGlyph(const UnsignedInt i) { std::tuple<Range2D, Range2D, Vector2> MagnumFontLayouter::doRenderGlyph(const UnsignedInt i) {
/* Position of the texture in the resulting glyph, texture coordinates */ /* Position of the texture in the resulting glyph, texture coordinates */
@ -242,4 +242,4 @@ std::tuple<Range2D, Range2D, Vector2> MagnumFontLayouter::doRenderGlyph(const Un
}} }}
CORRADE_PLUGIN_REGISTER(MagnumFont, Magnum::Text::MagnumFont, CORRADE_PLUGIN_REGISTER(MagnumFont, Magnum::Text::MagnumFont,
"cz.mosra.magnum.Text.AbstractFont/0.2.4") "cz.mosra.magnum.Text.AbstractFont/0.3")

10
src/MagnumPlugins/MagnumFont/MagnumFont.h

@ -29,6 +29,9 @@
* @brief Class @ref Magnum::Text::MagnumFont * @brief Class @ref Magnum::Text::MagnumFont
*/ */
#include "Magnum/configure.h"
#ifdef MAGNUM_TARGET_GL
#include "Magnum/Text/AbstractFont.h" #include "Magnum/Text/AbstractFont.h"
#include "Magnum/Trade/Trade.h" #include "Magnum/Trade/Trade.h"
@ -143,8 +146,8 @@ class MAGNUM_MAGNUMFONT_EXPORT MagnumFont: public AbstractFont {
MAGNUM_MAGNUMFONT_LOCAL UnsignedInt doGlyphId(char32_t character) override; MAGNUM_MAGNUMFONT_LOCAL UnsignedInt doGlyphId(char32_t character) override;
MAGNUM_MAGNUMFONT_LOCAL Vector2 doGlyphAdvance(UnsignedInt glyph) override; MAGNUM_MAGNUMFONT_LOCAL Vector2 doGlyphAdvance(UnsignedInt glyph) override;
MAGNUM_MAGNUMFONT_LOCAL Containers::Pointer<GlyphCache> doCreateGlyphCache() override; MAGNUM_MAGNUMFONT_LOCAL Containers::Pointer<AbstractGlyphCache> doCreateGlyphCache() override;
MAGNUM_MAGNUMFONT_LOCAL Containers::Pointer<AbstractLayouter> doLayout(const GlyphCache& cache, Float size, const std::string& text) override; MAGNUM_MAGNUMFONT_LOCAL Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache& cache, Float size, const std::string& text) override;
MAGNUM_MAGNUMFONT_LOCAL Metrics openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image); MAGNUM_MAGNUMFONT_LOCAL Metrics openInternal(Utility::Configuration&& conf, Trade::ImageData2D&& image);
@ -152,5 +155,8 @@ class MAGNUM_MAGNUMFONT_EXPORT MagnumFont: public AbstractFont {
}; };
}} }}
#else
#error this header is available only in the OpenGL build
#endif
#endif #endif

29
src/MagnumPlugins/MagnumFont/Test/CMakeLists.txt

@ -40,22 +40,37 @@ if(NOT BUILD_PLUGINS_STATIC)
# First replace ${} variables, then $<> generator expressions # First replace ${} variables, then $<> generator expressions
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h.in) ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
file(GENERATE OUTPUT $<TARGET_FILE_DIR:MagnumFontGLTest>/configure.h file(GENERATE OUTPUT $<TARGET_FILE_DIR:MagnumFontTest>/configure.h
INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in) INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
else() else()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h) ${CMAKE_CURRENT_BINARY_DIR}/configure.h)
endif() endif()
corrade_add_test(MagnumFontGLTest MagnumFontGLTest.cpp corrade_add_test(MagnumFontTest MagnumFontTest.cpp
LIBRARIES MagnumText MagnumTrade MagnumOpenGLTester LIBRARIES MagnumText MagnumTrade
FILES FILES
font.conf font.conf
font.tga) font.tga)
if(NOT BUILD_PLUGINS_STATIC) if(NOT BUILD_PLUGINS_STATIC)
target_include_directories(MagnumFontGLTest PRIVATE $<TARGET_FILE_DIR:MagnumFontGLTest>) target_include_directories(MagnumFontTest PRIVATE $<TARGET_FILE_DIR:MagnumFontTest>)
else() else()
target_include_directories(MagnumFontGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(MagnumFontTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(MagnumFontGLTest PRIVATE MagnumFont TgaImporter) target_link_libraries(MagnumFontTest PRIVATE MagnumFont TgaImporter)
endif()
set_target_properties(MagnumFontTest PROPERTIES FOLDER "MagnumPlugins/MagnumFont/Test")
if(BUILD_GL_TESTS)
corrade_add_test(MagnumFontGLTest MagnumFontGLTest.cpp
LIBRARIES MagnumText MagnumTrade MagnumOpenGLTester
FILES
font.conf
font.tga)
if(NOT BUILD_PLUGINS_STATIC)
target_include_directories(MagnumFontGLTest PRIVATE $<TARGET_FILE_DIR:MagnumFontTest>)
else()
target_include_directories(MagnumFontGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(MagnumFontGLTest PRIVATE MagnumFont TgaImporter)
endif()
set_target_properties(MagnumFontGLTest PROPERTIES FOLDER "MagnumPlugins/MagnumFont/Test")
endif() endif()
set_target_properties(MagnumFontGLTest PROPERTIES FOLDER "MagnumPlugins/MagnumFont/Test")

74
src/MagnumPlugins/MagnumFont/Test/MagnumFontGLTest.cpp

@ -38,9 +38,6 @@ namespace Magnum { namespace Text { namespace Test { namespace {
struct MagnumFontGLTest: GL::OpenGLTester { struct MagnumFontGLTest: GL::OpenGLTester {
explicit MagnumFontGLTest(); explicit MagnumFontGLTest();
void nonexistent();
void properties();
void layout();
void createGlyphCache(); void createGlyphCache();
/* Explicitly forbid system-wide plugin dependencies */ /* Explicitly forbid system-wide plugin dependencies */
@ -49,10 +46,7 @@ struct MagnumFontGLTest: GL::OpenGLTester {
}; };
MagnumFontGLTest::MagnumFontGLTest() { MagnumFontGLTest::MagnumFontGLTest() {
addTests({&MagnumFontGLTest::nonexistent, addTests({&MagnumFontGLTest::createGlyphCache});
&MagnumFontGLTest::properties,
&MagnumFontGLTest::layout,
&MagnumFontGLTest::createGlyphCache});
/* Load the plugins directly from the build tree. Otherwise they're static /* Load the plugins directly from the build tree. Otherwise they're static
and already loaded. */ and already loaded. */
@ -62,77 +56,13 @@ MagnumFontGLTest::MagnumFontGLTest() {
#endif #endif
} }
void MagnumFontGLTest::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 MagnumFontGLTest::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 MagnumFontGLTest::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 */
GlyphCache 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));
}
void MagnumFontGLTest::createGlyphCache() { void MagnumFontGLTest::createGlyphCache() {
Containers::Pointer<AbstractFont> font = _fontManager.instantiate("MagnumFont"); Containers::Pointer<AbstractFont> font = _fontManager.instantiate("MagnumFont");
CORRADE_VERIFY(font->openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f)); CORRADE_VERIFY(font->openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f));
/* Just testing that nothing crashes, asserts or errors */ /* Just testing that nothing crashes, asserts or errors */
Containers::Pointer<GlyphCache> cache = font->createGlyphCache(); Containers::Pointer<AbstractGlyphCache> cache = font->createGlyphCache();
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
CORRADE_VERIFY(cache); CORRADE_VERIFY(cache);

135
src/MagnumPlugins/MagnumFont/Test/MagnumFontTest.cpp

@ -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)

2
src/MagnumPlugins/MagnumFontConverter/CMakeLists.txt

@ -56,7 +56,7 @@ if(BUILD_PLUGINS_STATIC)
target_sources(MagnumFontConverter INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/importStaticPlugin.cpp) target_sources(MagnumFontConverter INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/importStaticPlugin.cpp)
endif() endif()
if(BUILD_GL_TESTS) if(BUILD_TESTS)
add_subdirectory(Test) add_subdirectory(Test)
endif() endif()

10
src/MagnumPlugins/MagnumFontConverter/MagnumFontConverter.cpp

@ -32,8 +32,8 @@
#include "Magnum/Image.h" #include "Magnum/Image.h"
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
#include "Magnum/Text/GlyphCache.h"
#include "Magnum/Text/AbstractFont.h" #include "Magnum/Text/AbstractFont.h"
#include "Magnum/Text/AbstractGlyphCache.h"
#include "MagnumPlugins/TgaImageConverter/TgaImageConverter.h" #include "MagnumPlugins/TgaImageConverter/TgaImageConverter.h"
namespace Magnum { namespace Text { namespace Magnum { namespace Text {
@ -46,7 +46,7 @@ auto MagnumFontConverter::doFeatures() const -> Features {
return Feature::ExportFont|Feature::ConvertData|Feature::MultiFile; return Feature::ExportFont|Feature::ConvertData|Feature::MultiFile;
} }
std::vector<std::pair<std::string, Containers::Array<char>>> MagnumFontConverter::doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const { std::vector<std::pair<std::string, Containers::Array<char>>> MagnumFontConverter::doExportFontToData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::u32string& characters) const {
Utility::Configuration configuration; Utility::Configuration configuration;
configuration.setValue("version", 1); configuration.setValue("version", 1);
@ -102,9 +102,7 @@ std::vector<std::pair<std::string, Containers::Array<char>>> MagnumFontConverter
std::copy(confStr.begin(), confStr.end(), confData.begin()); std::copy(confStr.begin(), confStr.end(), confData.begin());
/* Save cache image */ /* Save cache image */
Image2D image{PixelFormat::R8Unorm}; auto tgaData = Trade::TgaImageConverter().exportToData(cache.image());
cache.texture().image(0, image);
auto tgaData = Trade::TgaImageConverter().exportToData(image);
std::vector<std::pair<std::string, Containers::Array<char>>> out; std::vector<std::pair<std::string, Containers::Array<char>>> out;
out.emplace_back(filename + ".conf", std::move(confData)); out.emplace_back(filename + ".conf", std::move(confData));
@ -115,4 +113,4 @@ std::vector<std::pair<std::string, Containers::Array<char>>> MagnumFontConverter
}} }}
CORRADE_PLUGIN_REGISTER(MagnumFontConverter, Magnum::Text::MagnumFontConverter, CORRADE_PLUGIN_REGISTER(MagnumFontConverter, Magnum::Text::MagnumFontConverter,
"cz.mosra.magnum.Text.AbstractFontConverter/0.1.2") "cz.mosra.magnum.Text.AbstractFontConverter/0.2")

8
src/MagnumPlugins/MagnumFontConverter/MagnumFontConverter.h

@ -55,10 +55,10 @@ namespace Magnum { namespace Text {
@brief MagnumFont converter plugin @brief MagnumFont converter plugin
Expects filename prefix, creates two files, `prefix.conf` and `prefix.tga`. See Expects filename prefix, creates two files, `prefix.conf` and `prefix.tga`. See
@ref MagnumFont for more information about the font. @ref MagnumFont for more information about the font. The plugin requires the
passed @ref AbstractGlyphCache to support @ref GlyphCacheFeature::ImageDownload.
This plugin is available only on desktop OpenGL, as it uses @ref GL::Texture::image() This plugin depends on the @ref Text library and the
to read back the generated data. It depends on the @ref Text library and the
@ref Trade::TgaImageConverter "TgaImageConverter" plugin. It is built if @ref Trade::TgaImageConverter "TgaImageConverter" plugin. It is built if
`WITH_MAGNUMFONTCONVERTER` is enabled when building Magnum. To use as a `WITH_MAGNUMFONTCONVERTER` is enabled when building Magnum. To use as a
dynamic plugin, you need to load the @cpp "MagnumFontConverter" @ce plugin from dynamic plugin, you need to load the @cpp "MagnumFontConverter" @ce plugin from
@ -78,7 +78,7 @@ class MAGNUM_MAGNUMFONTCONVERTER_EXPORT MagnumFontConverter: public Text::Abstra
private: private:
MAGNUM_MAGNUMFONTCONVERTER_LOCAL Features doFeatures() const override; MAGNUM_MAGNUMFONTCONVERTER_LOCAL Features doFeatures() const override;
MAGNUM_MAGNUMFONTCONVERTER_LOCAL std::vector<std::pair<std::string, Containers::Array<char>>> doExportFontToData(AbstractFont& font, GlyphCache& cache, const std::string& filename, const std::u32string& characters) const override; MAGNUM_MAGNUMFONTCONVERTER_LOCAL std::vector<std::pair<std::string, Containers::Array<char>>> doExportFontToData(AbstractFont& font, AbstractGlyphCache& cache, const std::string& filename, const std::u32string& characters) const override;
}; };
}} }}

16
src/MagnumPlugins/MagnumFontConverter/Test/CMakeLists.txt

@ -37,23 +37,23 @@ if(NOT BUILD_PLUGINS_STATIC)
# First replace ${} variables, then $<> generator expressions # First replace ${} variables, then $<> generator expressions
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h.in) ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
file(GENERATE OUTPUT $<TARGET_FILE_DIR:MagnumFontConverterGLTest>/configure.h file(GENERATE OUTPUT $<TARGET_FILE_DIR:MagnumFontConverterTest>/configure.h
INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in) INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
else() else()
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h) ${CMAKE_CURRENT_BINARY_DIR}/configure.h)
endif() endif()
corrade_add_test(MagnumFontConverterGLTest MagnumFontConverterGLTest.cpp corrade_add_test(MagnumFontConverterTest MagnumFontConverterTest.cpp
LIBRARIES MagnumText MagnumTrade MagnumOpenGLTester) LIBRARIES MagnumText MagnumTrade)
if(NOT BUILD_PLUGINS_STATIC) if(NOT BUILD_PLUGINS_STATIC)
target_include_directories(MagnumFontConverterGLTest PRIVATE $<TARGET_FILE_DIR:MagnumFontConverterGLTest>) target_include_directories(MagnumFontConverterTest PRIVATE $<TARGET_FILE_DIR:MagnumFontConverterTest>)
else() else()
target_include_directories(MagnumFontConverterGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(MagnumFontConverterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(MagnumFontConverterGLTest PRIVATE target_link_libraries(MagnumFontConverterTest PRIVATE
MagnumFontConverter) # TgaImageConverter should get linked transitively MagnumFontConverter) # TgaImageConverter should get linked transitively
if(WITH_TGAIMPORTER) if(WITH_TGAIMPORTER)
target_link_libraries(MagnumFontConverterGLTest PRIVATE TgaImporter) target_link_libraries(MagnumFontConverterTest PRIVATE TgaImporter)
endif() endif()
endif() endif()
set_target_properties(MagnumFontConverterGLTest PROPERTIES FOLDER "MagnumPlugins/MagnumFontConverter/Test") set_target_properties(MagnumFontConverterTest PROPERTIES FOLDER "MagnumPlugins/MagnumFontConverter/Test")

38
src/MagnumPlugins/MagnumFontConverter/Test/MagnumFontConverterGLTest.cpp → src/MagnumPlugins/MagnumFontConverter/Test/MagnumFontConverterTest.cpp

@ -23,15 +23,15 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/File.h> #include <Corrade/TestSuite/Compare/File.h>
#include "Magnum/Image.h"
#include "Magnum/PixelFormat.h" #include "Magnum/PixelFormat.h"
#include "Magnum/GL/Context.h" #include "Magnum/Text/AbstractGlyphCache.h"
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/TextureFormat.h"
#include "Magnum/GL/OpenGLTester.h"
#include "Magnum/Text/GlyphCache.h"
#include "Magnum/Text/AbstractFont.h" #include "Magnum/Text/AbstractFont.h"
#include "Magnum/Text/AbstractFontConverter.h" #include "Magnum/Text/AbstractFontConverter.h"
#include "Magnum/Trade/AbstractImageConverter.h" #include "Magnum/Trade/AbstractImageConverter.h"
@ -42,8 +42,8 @@
namespace Magnum { namespace Text { namespace Test { namespace { namespace Magnum { namespace Text { namespace Test { namespace {
struct MagnumFontConverterGLTest: GL::OpenGLTester { struct MagnumFontConverterTest: TestSuite::Tester {
explicit MagnumFontConverterGLTest(); explicit MagnumFontConverterTest();
void exportFont(); void exportFont();
@ -53,8 +53,8 @@ struct MagnumFontConverterGLTest: GL::OpenGLTester {
PluginManager::Manager<Trade::AbstractImporter> _importerManager{"nonexistent"}; PluginManager::Manager<Trade::AbstractImporter> _importerManager{"nonexistent"};
}; };
MagnumFontConverterGLTest::MagnumFontConverterGLTest() { MagnumFontConverterTest::MagnumFontConverterTest() {
addTests({&MagnumFontConverterGLTest::exportFont}); addTests({&MagnumFontConverterTest::exportFont});
/* Load the plugins directly from the build tree. Otherwise they are static /* Load the plugins directly from the build tree. Otherwise they are static
and already loaded. */ and already loaded. */
@ -68,7 +68,7 @@ MagnumFontConverterGLTest::MagnumFontConverterGLTest() {
#endif #endif
} }
void MagnumFontConverterGLTest::exportFont() { void MagnumFontConverterTest::exportFont() {
/* Remove previously created files */ /* Remove previously created files */
Utility::Directory::rm(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.conf")); Utility::Directory::rm(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.conf"));
Utility::Directory::rm(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.tga")); Utility::Directory::rm(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.tga"));
@ -86,7 +86,7 @@ void MagnumFontConverterGLTest::exportFont() {
return {16.0f, 25.0f, -10.0f, 39.7333f}; return {16.0f, 25.0f, -10.0f, 39.7333f};
} }
Features doFeatures() const { return {}; } Features doFeatures() const { return {}; }
Containers::Pointer<AbstractLayouter> doLayout(const GlyphCache&, Float, const std::string&) { return nullptr; } Containers::Pointer<AbstractLayouter> doLayout(const AbstractGlyphCache&, Float, const std::string&) { return nullptr; }
UnsignedInt doGlyphId(const char32_t character) { UnsignedInt doGlyphId(const char32_t character) {
switch(character) { switch(character) {
@ -112,8 +112,15 @@ void MagnumFontConverterGLTest::exportFont() {
font.openFile({}, {}); font.openFile({}, {});
/* Create fake cache */ /* Create fake cache */
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::texture_rg); struct MyCache: AbstractGlyphCache {
GlyphCache cache(GL::TextureFormat::R8, Vector2i(1536), Vector2i(256), Vector2i(24)); explicit MyCache(): AbstractGlyphCache{Vector2i{1536}, Vector2i{24}} {}
GlyphCacheFeatures doFeatures() const override { return GlyphCacheFeature::ImageDownload; }
void doSetImage(const Vector2i&, const ImageView2D&) override {}
Image2D doImage() override {
return Image2D{PixelFormat::R8Unorm, Vector2i{256}, Containers::Array<char>{Containers::ValueInit, 256*256}};
}
} cache;
cache.insert(font.glyphId(U'W'), {25, 34}, {{0, 8}, {16, 128}}); cache.insert(font.glyphId(U'W'), {25, 34}, {{0, 8}, {16, 128}});
cache.insert(font.glyphId(U'e'), {25, 12}, {{16, 4}, {64, 32}}); cache.insert(font.glyphId(U'e'), {25, 12}, {{16, 4}, {64, 32}});
@ -130,7 +137,8 @@ void MagnumFontConverterGLTest::exportFont() {
if(!(_importerManager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) if(!(_importerManager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("TgaImporter plugin not enabled, not testing glyph cache contents"); CORRADE_SKIP("TgaImporter plugin not enabled, not testing glyph cache contents");
/* Verify font image, no need to test image contents, as the image is garbage anyway */ /* Verify font image, no need to test image contents, as the image is
garbage anyway */
Containers::Pointer<Trade::AbstractImporter> importer = _importerManager.instantiate("TgaImporter"); Containers::Pointer<Trade::AbstractImporter> importer = _importerManager.instantiate("TgaImporter");
CORRADE_VERIFY(importer->openFile(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.tga"))); CORRADE_VERIFY(importer->openFile(Utility::Directory::join(MAGNUMFONTCONVERTER_TEST_WRITE_DIR, "font.tga")));
Containers::Optional<Trade::ImageData2D> image = importer->image2D(0); Containers::Optional<Trade::ImageData2D> image = importer->image2D(0);
@ -141,4 +149,4 @@ void MagnumFontConverterGLTest::exportFont() {
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::Text::Test::MagnumFontConverterGLTest) CORRADE_TEST_MAIN(Magnum::Text::Test::MagnumFontConverterTest)
Loading…
Cancel
Save