mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
Added basic kerning support for TrueType and BMFont fonts (resolves issue #1055.)
This commit is contained in:
@@ -59,7 +59,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
std::string tag;
|
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")
|
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();
|
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)
|
bool BMFontRasterizer::accepts(love::filesystem::FileData *fontdef)
|
||||||
{
|
{
|
||||||
const char *data = (const char *) fontdef->getData();
|
const char *data = (const char *) fontdef->getData();
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "image/ImageData.h"
|
#include "image/ImageData.h"
|
||||||
|
|
||||||
// C++
|
// C++
|
||||||
#include <map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
@@ -50,6 +50,7 @@ public:
|
|||||||
GlyphData *getGlyphData(uint32 glyph) const override;
|
GlyphData *getGlyphData(uint32 glyph) const override;
|
||||||
int getGlyphCount() const override;
|
int getGlyphCount() const override;
|
||||||
bool hasGlyph(uint32 glyph) const override;
|
bool hasGlyph(uint32 glyph) const override;
|
||||||
|
float getKerning(uint32 leftglyph, uint32 rightglyph) const;
|
||||||
|
|
||||||
static bool accepts(love::filesystem::FileData *fontdef);
|
static bool accepts(love::filesystem::FileData *fontdef);
|
||||||
|
|
||||||
@@ -68,10 +69,13 @@ private:
|
|||||||
std::string fontFolder;
|
std::string fontFolder;
|
||||||
|
|
||||||
// Image pages, indexed by their page id.
|
// 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.
|
// 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;
|
int fontSize;
|
||||||
bool unicode;
|
bool unicode;
|
||||||
|
|||||||
@@ -95,5 +95,10 @@ bool Rasterizer::hasGlyphs(const std::string &text) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Rasterizer::getKerning(uint32 /*leftglyph*/, uint32 /*rightglyph*/) const
|
||||||
|
{
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
} // font
|
} // font
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -105,6 +105,11 @@ public:
|
|||||||
**/
|
**/
|
||||||
virtual bool hasGlyphs(const std::string &text) const;
|
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:
|
protected:
|
||||||
|
|
||||||
FontMetrics metrics;
|
FontMetrics metrics;
|
||||||
|
|||||||
@@ -165,6 +165,13 @@ bool TrueTypeRasterizer::hasGlyph(uint32 glyph) const
|
|||||||
return FT_Get_Char_Index(face, glyph) != 0;
|
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)
|
bool TrueTypeRasterizer::accepts(FT_Library library, love::Data *data)
|
||||||
{
|
{
|
||||||
const FT_Byte *fbase = (const FT_Byte *) data->getData();
|
const FT_Byte *fbase = (const FT_Byte *) data->getData();
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ public:
|
|||||||
virtual GlyphData *getGlyphData(uint32 glyph) const;
|
virtual GlyphData *getGlyphData(uint32 glyph) const;
|
||||||
virtual int getGlyphCount() const;
|
virtual int getGlyphCount() const;
|
||||||
virtual bool hasGlyph(uint32 glyph) const;
|
virtual bool hasGlyph(uint32 glyph) const;
|
||||||
|
virtual float getKerning(uint32 leftglyph, uint32 rightglyph) const;
|
||||||
|
|
||||||
static bool accepts(FT_Library library, love::Data *data);
|
static bool accepts(FT_Library library, love::Data *data);
|
||||||
|
|
||||||
|
|||||||
@@ -316,6 +316,29 @@ const Font::Glyph &Font::findGlyph(uint32 glyph)
|
|||||||
return addGlyph(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
|
float Font::getHeight() const
|
||||||
{
|
{
|
||||||
return (float) height;
|
return (float) height;
|
||||||
@@ -337,6 +360,8 @@ std::vector<Font::DrawCommand> Font::generateVertices(const std::string &text, s
|
|||||||
size_t vertstartsize = vertices.size();
|
size_t vertstartsize = vertices.size();
|
||||||
vertices.reserve(vertstartsize + text.length() * 4);
|
vertices.reserve(vertstartsize + text.length() * 4);
|
||||||
|
|
||||||
|
uint32 prevglyph = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
|
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;
|
dy = offset.y;
|
||||||
drawcommands.clear();
|
drawcommands.clear();
|
||||||
vertices.resize(vertstartsize);
|
vertices.resize(vertstartsize);
|
||||||
|
prevglyph = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add kerning to the current horizontal offset.
|
||||||
|
dx += getKerning(prevglyph, g);
|
||||||
|
|
||||||
if (glyph.texture != 0)
|
if (glyph.texture != 0)
|
||||||
{
|
{
|
||||||
// Copy the vertices and set their proper relative positions.
|
// Copy the vertices and set their proper relative positions.
|
||||||
for (int j = 0; j < 4; j++)
|
for (int j = 0; j < 4; j++)
|
||||||
{
|
{
|
||||||
vertices.push_back(glyph.vertices[j]);
|
vertices.push_back(glyph.vertices[j]);
|
||||||
vertices.back().x += dx;
|
vertices.back().x += dx /*+ kerning*/;
|
||||||
vertices.back().y += dy + lineheight;
|
vertices.back().y += dy /*+ kerning.y*/ + lineheight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if glyph texture has changed since the last iteration.
|
// 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.
|
// Account for extra spacing given to space characters.
|
||||||
if (g == ' ' && extra_spacing != 0.0f)
|
if (g == ' ' && extra_spacing != 0.0f)
|
||||||
dx = floorf(dx + extra_spacing);
|
dx = floorf(dx + extra_spacing);
|
||||||
|
|
||||||
|
prevglyph = g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (utf8::exception &e)
|
catch (utf8::exception &e)
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ private:
|
|||||||
love::font::GlyphData *getRasterizerGlyphData(uint32 glyph);
|
love::font::GlyphData *getRasterizerGlyphData(uint32 glyph);
|
||||||
const Glyph &addGlyph(uint32 glyph);
|
const Glyph &addGlyph(uint32 glyph);
|
||||||
const Glyph &findGlyph(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);
|
void printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands, const std::vector<GlyphVertex> &vertices);
|
||||||
|
|
||||||
std::vector<StrongRef<love::font::Rasterizer>> rasterizers;
|
std::vector<StrongRef<love::font::Rasterizer>> rasterizers;
|
||||||
@@ -227,6 +228,9 @@ private:
|
|||||||
// maps glyphs to glyph texture information
|
// maps glyphs to glyph texture information
|
||||||
std::unordered_map<uint32, Glyph> glyphs;
|
std::unordered_map<uint32, Glyph> glyphs;
|
||||||
|
|
||||||
|
// map of left/right glyph pairs to horizontal kerning.
|
||||||
|
std::unordered_map<uint64, float> kerning;
|
||||||
|
|
||||||
FontType type;
|
FontType type;
|
||||||
Texture::Filter filter;
|
Texture::Filter filter;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user