Added basic kerning support for TrueType and BMFont fonts (resolves issue #1055.)

This commit is contained in:
Alex Szpakowski
2015-07-02 21:07:34 -03:00
parent 4550409ffa
commit bf432aff7c
8 changed files with 80 additions and 7 deletions
+18 -2
View File
@@ -59,7 +59,7 @@ public:
private:
std::string tag;
std::map<std::string, std::string> attributes;
std::unordered_map<std::string, std::string> 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();
+7 -3
View File
@@ -27,7 +27,7 @@
#include "image/ImageData.h"
// C++
#include <map>
#include <unordered_map>
#include <vector>
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<int, StrongRef<image::ImageData>> images;
std::unordered_map<int, StrongRef<image::ImageData>> images;
// Glyph characters, indexed by their glyph id.
std::map<uint32, BMFontCharacter> characters;
std::unordered_map<uint32, BMFontCharacter> characters;
// Kerning information, indexed by two (packed) characters.
std::unordered_map<uint64, int> kerning;
int fontSize;
bool unicode;
+5
View File
@@ -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
+5
View File
@@ -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;
@@ -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();
@@ -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);
+33 -2
View File
@@ -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::DrawCommand> Font::generateVertices(const std::string &text, s
size_t vertstartsize = vertices.size();
vertices.reserve(vertstartsize + text.length() * 4);
uint32 prevglyph = 0;
try
{
utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
@@ -370,17 +395,21 @@ std::vector<Font::DrawCommand> 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::DrawCommand> 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)
+4
View File
@@ -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<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices);
std::vector<StrongRef<love::font::Rasterizer>> rasterizers;
@@ -227,6 +228,9 @@ private:
// maps glyphs to glyph texture information
std::unordered_map<uint32, Glyph> glyphs;
// map of left/right glyph pairs to horizontal kerning.
std::unordered_map<uint64, float> kerning;
FontType type;
Texture::Filter filter;