From 12f719f177374c8f6141e3ea2b5685500c6338a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 3 Mar 2013 01:06:18 +0100 Subject: [PATCH] Text: prerendering Font for use with distance-field rendering. Currently there is no builtin shader capable of it, will come later. --- src/Text/Font.cpp | 39 ++++++++++++++++++++++++++++++--------- src/Text/Font.h | 16 ++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/Text/Font.cpp b/src/Text/Font.cpp index 95df89380..77b3b99ef 100644 --- a/src/Text/Font.cpp +++ b/src/Text/Font.cpp @@ -26,6 +26,7 @@ #include "Extensions.h" #include "Image.h" #include "TextureTools/Atlas.h" +#include "TextureTools/DistanceField.h" namespace Magnum { namespace Text { @@ -61,7 +62,7 @@ void Font::finishConstruction() { ->setMagnificationFilter(Texture2D::Filter::LinearInterpolation); } -void Font::prerender(const std::string& characters, const Vector2i& atlasSize) { +void Font::prerenderInternal(const std::string& characters, const Vector2i& atlasSize, const Int radius, Texture2D* output) { glyphs.clear(); /** @bug Crash when atlas is too small */ @@ -81,6 +82,7 @@ void Font::prerender(const std::string& characters, const Vector2i& atlasSize) { charIndices.erase(std::unique(charIndices.begin(), charIndices.end()), charIndices.end()); /* Sizes of all characters */ + const Vector2i padding = Vector2i(radius); std::vector charSizes; charSizes.reserve(charIndices.size()); for(FT_UInt c: charIndices) { @@ -89,7 +91,7 @@ void Font::prerender(const std::string& characters, const Vector2i& atlasSize) { } /* Create texture atlas */ - const std::vector charPositions = TextureTools::atlas(atlasSize, charSizes); + const std::vector charPositions = TextureTools::atlas(atlasSize, charSizes, padding); /* Render all characters to the atlas and create character map */ glyphs.reserve(charPositions.size()); @@ -97,7 +99,7 @@ void Font::prerender(const std::string& characters, const Vector2i& atlasSize) { Image2D image(atlasSize, Image2D::Format::Red, Image2D::Type::UnsignedByte, pixmap); for(std::size_t i = 0; i != charPositions.size(); ++i) { /* Load and render glyph */ - /** @todo B&W only */ + /** @todo B&W only if radius != 0 */ FT_GlyphSlot glyph = _ftFont->glyph; CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Load_Glyph(_ftFont, charIndices[i], FT_LOAD_DEFAULT) == 0); CORRADE_INTERNAL_ASSERT_OUTPUT(FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) == 0); @@ -112,21 +114,40 @@ void Font::prerender(const std::string& characters, const Vector2i& atlasSize) { /* Save character texture position and texture coordinates for given character index */ CORRADE_INTERNAL_ASSERT_OUTPUT(glyphs.insert({charIndices[i], std::make_tuple( - Rectangle::fromSize(Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height())/_size, - Vector2(charPositions[i].size())/_size), - Rectangle(Vector2(charPositions[i].bottomLeft())/atlasSize, - Vector2(charPositions[i].topRight())/atlasSize) + Rectangle::fromSize((Vector2(glyph->bitmap_left, glyph->bitmap_top-charPositions[i].height()) - Vector2(radius))/_size, + Vector2(charPositions[i].size() + 2*padding)/_size), + Rectangle(Vector2(charPositions[i].bottomLeft() - padding)/atlasSize, + Vector2(charPositions[i].topRight() + padding)/atlasSize) )}).second); } /* Set texture data */ #ifndef MAGNUM_TARGET_GLES - _texture.setImage(0, Texture2D::InternalFormat::R8, &image); + output->setImage(0, Texture2D::InternalFormat::R8, &image); #else - _texture.setImage(0, Texture2D::InternalFormat::Red, &image); + output->setImage(0, Texture2D::InternalFormat::Red, &image); #endif } +void Font::prerender(const std::string& characters, const Vector2i& atlasSize) { + prerenderInternal(characters, atlasSize, 0, &_texture); +} + +void Font::prerenderDistanceField(const std::string& characters, const Vector2i& atlasSize, const Vector2i& distanceFieldAtlasSize, Int radius) { + MAGNUM_ASSERT_EXTENSION_SUPPORTED(Extensions::GL::ARB::texture_storage); + + /* Render input texture */ + Texture2D input; + input.setWrapping(Texture2D::Wrapping::ClampToEdge) + ->setMinificationFilter(Texture2D::Filter::LinearInterpolation) + ->setMagnificationFilter(Texture2D::Filter::LinearInterpolation); + prerenderInternal(characters, atlasSize, radius, &input); + + /* Create distance field from input texture */ + _texture.setStorage(1, Texture2D::InternalFormat::R8, distanceFieldAtlasSize); + TextureTools::distanceField(&input, &_texture, Rectanglei::fromSize({}, distanceFieldAtlasSize), radius); +} + void Font::destroy() { if(!_ftFont) return; diff --git a/src/Text/Font.h b/src/Text/Font.h index 247e003d5..6745ddf90 100644 --- a/src/Text/Font.h +++ b/src/Text/Font.h @@ -96,6 +96,21 @@ class MAGNUM_TEXT_EXPORT Font { */ void prerender(const std::string& characters, const Vector2i& atlasSize); + /** + * @brief Prerender given character set for use with distance-field rendering + * @param characters UTF-8 characters to render + * @param sourceAtlasSize Size of distance field source atlas + * @param atlasSize Size of resulting atlas + * @param radius Max lookup radius for distance-field creation + * + * Creates new atlas with prerendered characters, replacing the + * previous one (if any). See TextureTools::distanceField() for more + * information. + * @attention @p sourceAtlasSize must be large enough to contain all + * rendered glyphs with padding given by @p radius. + */ + void prerenderDistanceField(const std::string& characters, const Vector2i& atlasSize, const Vector2i& distanceFieldAtlasSize, Int radius); + ~Font(); /** @brief Move constructor */ @@ -133,6 +148,7 @@ class MAGNUM_TEXT_EXPORT Font { void MAGNUM_TEXT_LOCAL finishConstruction(); void MAGNUM_TEXT_LOCAL destroy(); void MAGNUM_TEXT_LOCAL move(); + void MAGNUM_TEXT_LOCAL prerenderInternal(const std::string& characters, const Vector2i& atlasSize, const Int radius, Texture2D* output); std::unordered_map> glyphs; Texture2D _texture;