Browse Source

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

rdb 8 years ago
parent
commit
e1c0e7d1d4

+ 6 - 0
panda/src/text/config_text.cxx

@@ -48,6 +48,12 @@ ConfigVariableBool text_dynamic_merge
           "operation.  Usually it's a performance "
           "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
 ("text-anisotropic-degree", 1,
  PRC_DESC("This is the default anisotropic-degree that is set on dynamic "

+ 1 - 0
panda/src/text/config_text.h

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

+ 26 - 0
panda/src/text/dynamicTextFont.cxx

@@ -278,6 +278,32 @@ get_glyph(int character, CPT(TextGlyph) &glyph) {
   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.

+ 1 - 0
panda/src/text/dynamicTextFont.h

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

+ 16 - 0
panda/src/text/textAssembler.cxx

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

+ 10 - 0
panda/src/text/textFont.cxx

@@ -54,6 +54,16 @@ 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;
+}
+
 /**
  *
  */

+ 2 - 0
panda/src/text/textFont.h

@@ -74,6 +74,8 @@ PUBLISHED:
 
   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;
 
 public: