diff --git a/src/modules/font/BMFontRasterizer.cpp b/src/modules/font/BMFontRasterizer.cpp index 3056017dd..70b3db563 100644 --- a/src/modules/font/BMFontRasterizer.cpp +++ b/src/modules/font/BMFontRasterizer.cpp @@ -59,7 +59,7 @@ public: private: std::string tag; - std::map attributes; + std::unordered_map attributes; }; @@ -226,7 +226,12 @@ void BMFontRasterizer::parseConfig(const std::string &configtext) } else if (tag == "kerning") { - // TODO + uint32 firstid = (uint32) cline.getAttributeInt("first"); + uint32 secondid = (uint32) cline.getAttributeInt("second"); + + uint64 packedids = ((uint64) firstid << 32) | (uint64) secondid; + + kerning[packedids] = cline.getAttributeInt("amount"); } } @@ -309,6 +314,17 @@ bool BMFontRasterizer::hasGlyph(uint32 glyph) const return characters.find(glyph) != characters.end(); } +float BMFontRasterizer::getKerning(uint32 leftglyph, uint32 rightglyph) const +{ + uint64 packedglyphs = ((uint64) leftglyph << 32) | (uint64) rightglyph; + + auto it = kerning.find(packedglyphs); + if (it != kerning.end()) + return it->second; + + return 0.0f; +} + bool BMFontRasterizer::accepts(love::filesystem::FileData *fontdef) { const char *data = (const char *) fontdef->getData(); diff --git a/src/modules/font/BMFontRasterizer.h b/src/modules/font/BMFontRasterizer.h index 1901108be..40591d081 100644 --- a/src/modules/font/BMFontRasterizer.h +++ b/src/modules/font/BMFontRasterizer.h @@ -27,7 +27,7 @@ #include "image/ImageData.h" // C++ -#include +#include #include namespace love @@ -50,6 +50,7 @@ public: GlyphData *getGlyphData(uint32 glyph) const override; int getGlyphCount() const override; bool hasGlyph(uint32 glyph) const override; + float getKerning(uint32 leftglyph, uint32 rightglyph) const; static bool accepts(love::filesystem::FileData *fontdef); @@ -68,10 +69,13 @@ private: std::string fontFolder; // Image pages, indexed by their page id. - std::map> images; + std::unordered_map> images; // Glyph characters, indexed by their glyph id. - std::map characters; + std::unordered_map characters; + + // Kerning information, indexed by two (packed) characters. + std::unordered_map kerning; int fontSize; bool unicode; diff --git a/src/modules/font/Rasterizer.cpp b/src/modules/font/Rasterizer.cpp index eecb58925..a574888b3 100644 --- a/src/modules/font/Rasterizer.cpp +++ b/src/modules/font/Rasterizer.cpp @@ -95,5 +95,10 @@ bool Rasterizer::hasGlyphs(const std::string &text) const return true; } +float Rasterizer::getKerning(uint32 /*leftglyph*/, uint32 /*rightglyph*/) const +{ + return 0.0f; +} + } // font } // love diff --git a/src/modules/font/Rasterizer.h b/src/modules/font/Rasterizer.h index 977522235..db5b163b4 100644 --- a/src/modules/font/Rasterizer.h +++ b/src/modules/font/Rasterizer.h @@ -105,6 +105,11 @@ public: **/ virtual bool hasGlyphs(const std::string &text) const; + /** + * Gets the amount of horizontal kerning between two glyphs. + **/ + virtual float getKerning(uint32 leftglyph, uint32 rightglyph) const; + protected: FontMetrics metrics; diff --git a/src/modules/font/freetype/TrueTypeRasterizer.cpp b/src/modules/font/freetype/TrueTypeRasterizer.cpp index b88ca9d1b..29c77fdd6 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.cpp +++ b/src/modules/font/freetype/TrueTypeRasterizer.cpp @@ -165,6 +165,13 @@ bool TrueTypeRasterizer::hasGlyph(uint32 glyph) const return FT_Get_Char_Index(face, glyph) != 0; } +float TrueTypeRasterizer::getKerning(uint32 leftglyph, uint32 rightglyph) const +{ + FT_Vector kerning = {}; + FT_Get_Kerning(face, leftglyph, rightglyph, FT_KERNING_DEFAULT, &kerning); + return float(kerning.x >> 6); +} + bool TrueTypeRasterizer::accepts(FT_Library library, love::Data *data) { const FT_Byte *fbase = (const FT_Byte *) data->getData(); diff --git a/src/modules/font/freetype/TrueTypeRasterizer.h b/src/modules/font/freetype/TrueTypeRasterizer.h index f873c5275..5b0acb838 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.h +++ b/src/modules/font/freetype/TrueTypeRasterizer.h @@ -52,6 +52,7 @@ public: virtual GlyphData *getGlyphData(uint32 glyph) const; virtual int getGlyphCount() const; virtual bool hasGlyph(uint32 glyph) const; + virtual float getKerning(uint32 leftglyph, uint32 rightglyph) const; static bool accepts(FT_Library library, love::Data *data); diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 440ed1253..4d13d1f46 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -316,6 +316,29 @@ const Font::Glyph &Font::findGlyph(uint32 glyph) return addGlyph(glyph); } +float Font::getKerning(uint32 leftglyph, uint32 rightglyph) +{ + uint64 packedglyphs = ((uint64) leftglyph << 32) | (uint64) rightglyph; + + const auto it = kerning.find(packedglyphs); + if (it != kerning.end()) + return it->second; + + float k = rasterizers[0]->getKerning(leftglyph, rightglyph); + + for (const auto &r : rasterizers) + { + if (r->hasGlyph(leftglyph) && r->hasGlyph(rightglyph)) + { + k = r->getKerning(leftglyph, rightglyph); + break; + } + } + + kerning[packedglyphs] = k; + return k; +} + float Font::getHeight() const { return (float) height; @@ -337,6 +360,8 @@ std::vector Font::generateVertices(const std::string &text, s size_t vertstartsize = vertices.size(); vertices.reserve(vertstartsize + text.length() * 4); + uint32 prevglyph = 0; + try { utf8::iterator i(text.begin(), text.begin(), text.end()); @@ -370,17 +395,21 @@ std::vector Font::generateVertices(const std::string &text, s dy = offset.y; drawcommands.clear(); vertices.resize(vertstartsize); + prevglyph = 0; continue; } + // Add kerning to the current horizontal offset. + dx += getKerning(prevglyph, g); + if (glyph.texture != 0) { // Copy the vertices and set their proper relative positions. for (int j = 0; j < 4; j++) { vertices.push_back(glyph.vertices[j]); - vertices.back().x += dx; - vertices.back().y += dy + lineheight; + vertices.back().x += dx /*+ kerning*/; + vertices.back().y += dy /*+ kerning.y*/ + lineheight; } // Check if glyph texture has changed since the last iteration. @@ -403,6 +432,8 @@ std::vector Font::generateVertices(const std::string &text, s // Account for extra spacing given to space characters. if (g == ' ' && extra_spacing != 0.0f) dx = floorf(dx + extra_spacing); + + prevglyph = g; } } catch (utf8::exception &e) diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index de0113d3c..cf1dbca28 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -211,6 +211,7 @@ private: love::font::GlyphData *getRasterizerGlyphData(uint32 glyph); const Glyph &addGlyph(uint32 glyph); const Glyph &findGlyph(uint32 glyph); + float getKerning(uint32 leftglyph, uint32 rightglyph); void printv(const Matrix4 &t, const std::vector &drawcommands, const std::vector &vertices); std::vector> rasterizers; @@ -227,6 +228,9 @@ private: // maps glyphs to glyph texture information std::unordered_map glyphs; + // map of left/right glyph pairs to horizontal kerning. + std::unordered_map kerning; + FontType type; Texture::Filter filter;