text: add experimental kerning support, enabled by 'text-kerning'

This commit is contained in:
rdb 2017-03-27 19:15:09 +02:00
parent 4080e03d05
commit e1c0e7d1d4
7 changed files with 62 additions and 0 deletions

View File

@ -48,6 +48,12 @@ ConfigVariableBool text_dynamic_merge
"operation. Usually it's a performance " "operation. Usually it's a performance "
"advantage to keep this true. See TextNode::set_flatten_flags().")); "advantage to keep this true. See TextNode::set_flatten_flags()."));
ConfigVariableBool text_kerning
("text-kerning", false,
PRC_DESC("Set this true to enable kerning when the font provides kerning "
"tables. This can result in more aesthetically pleasing spacing "
"between individual glyphs."));
ConfigVariableInt text_anisotropic_degree ConfigVariableInt text_anisotropic_degree
("text-anisotropic-degree", 1, ("text-anisotropic-degree", 1,
PRC_DESC("This is the default anisotropic-degree that is set on dynamic " PRC_DESC("This is the default anisotropic-degree that is set on dynamic "

View File

@ -30,6 +30,7 @@ NotifyCategoryDecl(text, EXPCL_PANDA_TEXT, EXPTP_PANDA_TEXT);
extern ConfigVariableBool text_flatten; extern ConfigVariableBool text_flatten;
extern ConfigVariableBool text_dynamic_merge; extern ConfigVariableBool text_dynamic_merge;
extern ConfigVariableBool text_kerning;
extern ConfigVariableInt text_anisotropic_degree; extern ConfigVariableInt text_anisotropic_degree;
extern ConfigVariableInt text_texture_margin; extern ConfigVariableInt text_texture_margin;
extern ConfigVariableDouble text_poly_margin; extern ConfigVariableDouble text_poly_margin;

View File

@ -278,6 +278,32 @@ get_glyph(int character, CPT(TextGlyph) &glyph) {
return (glyph_index != 0); return (glyph_index != 0);
} }
/**
* Returns the amount by which to offset the second glyph when it directly
* follows the first glyph. This is an additional offset that is added on top
* of the advance.
*/
PN_stdfloat DynamicTextFont::
get_kerning(int first, int second) const {
if (!_is_valid) {
return 0;
}
FT_Face face = acquire_face();
if (!FT_HAS_KERNING(face)) {
release_face(face);
return 0;
}
int first_index = FT_Get_Char_Index(face, first);
int second_index = FT_Get_Char_Index(face, second);
FT_Vector delta;
FT_Get_Kerning(face, first_index, second_index, FT_KERNING_DEFAULT, &delta);
release_face(face);
return delta.x / (_font_pixels_per_unit * 64);
}
/** /**
* Called from both constructors to set up some initial values. * Called from both constructors to set up some initial values.

View File

@ -123,6 +123,7 @@ PUBLISHED:
public: public:
virtual bool get_glyph(int character, CPT(TextGlyph) &glyph); virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
virtual PN_stdfloat get_kerning(int first, int second) const;
private: private:
void initialize(); void initialize();

View File

@ -609,6 +609,8 @@ assemble_text() {
* Returns the width of a single character, according to its associated font. * Returns the width of a single character, according to its associated font.
* This also correctly calculates the width of cheesy ligatures and accented * This also correctly calculates the width of cheesy ligatures and accented
* characters, which may not exist in the font as such. * characters, which may not exist in the font as such.
*
* This does not take kerning into account, however.
*/ */
PN_stdfloat TextAssembler:: PN_stdfloat TextAssembler::
calc_width(wchar_t character, const TextProperties &properties) { calc_width(wchar_t character, const TextProperties &properties) {
@ -1399,6 +1401,9 @@ assemble_row(TextAssembler::TextRow &row,
PN_stdfloat xpos = 0.0f; PN_stdfloat xpos = 0.0f;
align = TextProperties::A_left; align = TextProperties::A_left;
// Remember previous character, for kerning.
int prev_char = -1;
bool underscore = false; bool underscore = false;
PN_stdfloat underscore_start = 0.0f; PN_stdfloat underscore_start = 0.0f;
const TextProperties *underscore_properties = NULL; const TextProperties *underscore_properties = NULL;
@ -1450,11 +1455,13 @@ assemble_row(TextAssembler::TextRow &row,
if (character == ' ') { if (character == ' ') {
// A space is a special case. // A space is a special case.
xpos += properties->get_glyph_scale() * properties->get_text_scale() * font->get_space_advance(); xpos += properties->get_glyph_scale() * properties->get_text_scale() * font->get_space_advance();
prev_char = -1;
} else if (character == '\t') { } else if (character == '\t') {
// So is a tab character. // So is a tab character.
PN_stdfloat tab_width = properties->get_tab_width(); PN_stdfloat tab_width = properties->get_tab_width();
xpos = (floor(xpos / tab_width) + 1.0f) * tab_width; xpos = (floor(xpos / tab_width) + 1.0f) * tab_width;
prev_char = -1;
} else if (character == text_soft_hyphen_key) { } else if (character == text_soft_hyphen_key) {
// And so is the 'soft-hyphen' key character. // And so is the 'soft-hyphen' key character.
@ -1493,6 +1500,7 @@ assemble_row(TextAssembler::TextRow &row,
placed_glyphs.push_back(placement); placed_glyphs.push_back(placement);
xpos += advance * glyph_scale; xpos += advance * glyph_scale;
prev_char = -1;
} else { } else {
// A printable character. // A printable character.
@ -1521,6 +1529,14 @@ assemble_row(TextAssembler::TextRow &row,
<< "\n"; << "\n";
} }
// Add the kerning delta.
if (text_kerning) {
if (prev_char != -1) {
xpos += font->get_kerning(prev_char, character);
}
prev_char = character;
}
// Build up a GlyphPlacement, indicating all of the Geoms that go into // Build up a GlyphPlacement, indicating all of the Geoms that go into
// this character. Normally, there is only one Geom per character, but // this character. Normally, there is only one Geom per character, but
// it may involve multiple Geoms if we need to add cheesy accents or // it may involve multiple Geoms if we need to add cheesy accents or

View File

@ -54,6 +54,16 @@ TextFont::
~TextFont() { ~TextFont() {
} }
/**
* Returns the amount by which to offset the second glyph when it directly
* follows the first glyph. This is an additional offset that is added on top
* of the advance.
*/
PN_stdfloat TextFont::
get_kerning(int first, int second) const {
return 0;
}
/** /**
* *
*/ */

View File

@ -74,6 +74,8 @@ PUBLISHED:
INLINE CPT(TextGlyph) get_glyph(int character); INLINE CPT(TextGlyph) get_glyph(int character);
virtual PN_stdfloat get_kerning(int first, int second) const;
virtual void write(ostream &out, int indent_level) const; virtual void write(ostream &out, int indent_level) const;
public: public: