3
\$\begingroup\$

Drawing multi-colored text or highlighted text in XNA/MonoGame is pretty annoying, and the standard way I've seen to do it is to just to make multiple SpriteBatch.DrawString calls, and place them using the x-coordinates given by SpriteFont.MeasureString. This is fine if you're highlighting whole words or blocks of text, but if you only want to highlight select letters inside of a word, you get a kerning nightmare:

kerning

Sometimes this looks alright, but not consistently and I can't think or find a good way to space out the letters properly.

Therefore, I would like to know if there's either a better way to draw highlighted text like this in XNA/MonoGame, or a way to pull kerning data out of a font so I can space the letters properly or some other fancy way to do it using masks or whatnot.

Thanks in advance!

\$\endgroup\$
0

2 Answers 2

3
\$\begingroup\$

What I do is ignore the built in SpriteFont's in MonoGame and roll my own. If you use a tool like BMFont to generate the texture, writing a basic font renderer is pretty easy.

First you'll need to grab a BmFont XML Serializer so that you can load the font file into C#. You can find one on pastebin here. http://pastebin.com/x3Z2mDC6

Then you'll need to write a basic font renderer. Here's one I've used before:

public class FontRenderer
{
    public FontRenderer (FontFile fontFile, Texture2D fontTexture)
    {
        _fontFile = fontFile;
        _texture = fontTexture;
        _characterMap = new Dictionary<char, FontChar>();

        foreach(var fontCharacter in _fontFile.Chars)
        {
            char c = (char)fontCharacter.ID;
            _characterMap.Add(c, fontCharacter);
        }
    }

    private Dictionary<char, FontChar> _characterMap;
    private FontFile _fontFile;
    private Texture2D _texture;
    public void DrawText(SpriteBatch spriteBatch, int x, int y, string text)
    {
        int dx = x;
        int dy = y;
        foreach(char c in text)
        {
            FontChar fc;
            if(_characterMap.TryGetValue(c, out fc))
            {
                var sourceRectangle = new Rectangle(fc.X, fc.Y, fc.Width, fc.Height);
                var position = new Vector2(dx + fc.XOffset, dy + fc.YOffset);

                spriteBatch.Draw(_texture, position, sourceRectangle, Color.White);
                dx += fc.XAdvance;
            }
        }
    }
}

Obviously you'll also need to make some changes to allow each letter to be a different color. Once you've got the basic framework in place that should be pretty easy.

I have a more complete tutorial on my blog here:

http://www.craftworkgames.com/blog/tutorial-bmfont-rendering-with-monogame/

\$\endgroup\$
1
  • \$\begingroup\$ Well, it'll take a bit of tinkering for it to work, but thanks for suggesting a good alternative to the MonoGame SpriteFonts's! \$\endgroup\$ Commented Sep 7, 2014 at 16:35
1
\$\begingroup\$

The font format for XNA/MonoGame still stores the required info for kerning - obviously it needs it to draw text itself! You just need to get at it and use it from your own code.

In MonoGame you can directly access the gylph data (see this source file). The Gylph structure contains the kerning information you need to layout your text correctly.

(MonoGame is open source, so this was correct at time of writing, and may change.)

If you look at DrawInto and MeasureString in MonoGame, you can figure out what is actually being done with the kerning data. It should be reasonably straightforward to reuse/reference that for your own string drawing.

If you use XNA, the same data is available. Use ILSpy and reflection to get access to it. The kerning information in is simply ABC data returned from GetCharABCWidths in the win32 API (it's the same data for both XNA and MonoGame, but stored slightly differently).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .