Creating and using bitmap fonts in XNA


As mentioned in a previous post, there is a clear need for a bitmap font generator that provides proper Unicode support.


To address this need, I created BMFontGen.exe. This program can generate a bitmap font from any of the fonts currently installed on your system and it provides a variety of options for controlling which glyphs get placed in the font and how they appear. More details about the tool (including a download link) are given in this document, but for our purposes it suffices to know that BMFontGen takes a font name and a font size and produces an XML file (containing the font description) and a collection of PNG files (that contain the glyph bitmaps).


To use these fonts in an XNA game, you need some code that can load these files and let you draw a string of text on the screen. To fill this role, I created the BitmapFont class. This class handles the font loading and exposes a set of DrawString methods that do what you would expect them to do.


To demonstrate the class in action, I’ve created a simple demo app (attached to this post – see link at bottom) which I’ve cleverly named “BitmapFontDemo”. Here is a screenshot from the app that shows off some of the capabilities of the font renderer.



The BitmapFont class is intended to provide basic text rendering services only, so don’t expect it to handle linebreaks or format text in a rectangle or provide any other advanced text options. However, I’ll be adding functionality to it as time goes on, and I also intend to release other game support classes that build upon the base functionality provided by BitmapFont.


This is the first release for this tool, so let me know if you find this useful or if you think there’re features missing. I’m curious to see games that make use of these fonts (even if I can’t read them ^_^).

BitmapFontDemo.zip

Comments (19)

  1. Ashley Allen says:

    Thanks dude. You rule!

  2. Peter K says:

    Works great, thanks for sharing.

  3. SePPiE X says:

    Awesome class! This is gonna save me SO much time.. Thank you very much!

  4. Jim Welch says:

    This is great. I only have 1 recommendation. Can you add a readonly property of FontFilename to the BitmapFont class? I’ve done so for my project, but I think I’ll be checking in and updating the class with your new improvements. I’m using that prop to check to see if the font has already been loaded by looping through a List<BitmapFont>, etc.

  5. Gary has several informative links in his XNA Framework Content Pipeline post.  He also gives us a couple…

  6. MadJack McMad says:

    You’re a hero, thank you for this.

  7. David says:

    The biggest missing feature is that there aren’t any “button graphics” included with XNA. I would think pretty much every game developed would want them. (I’m saying, a bitmap for A, B, X, Y, right shoulder, and so forth).

    In any event, you are correct in your premise about this issue: this kind of functionality needs to be rolled into XNA proper.

  8. PeteB says:

    Great work cheers. David’s comment is a good suggestion other than that, great job helped me a lot 😀

    Pete

  9. XNA Diaries says:

    The ClearType&amp;nbsp;text rendering hint (option: -trh ct-grid) tells&amp;nbsp;BMFontGen&amp;nbsp;to apply&amp;nbsp;ClearType…

  10. Matt Moore says:

    How does one properly dispose of this prior to a GraphicsDevice.Reset?

    I am getting errors on my device.Reset while changing resolutions.

    I’ve created a Dispose() to your class that disposes of the m_sb (the only instance to be in the default pool) but that has not worked.

    MyFont.Dispose();
    device.Reset(MyPP);

    It throws exception at that line prior to getting to my device.Rest and device.Lost handlers.

    [3408] Direct3D9: (ERROR) :The following D3DPOOL_DEFAULT surfaces/buffers/textures still exist

    [3408] Direct3D9: (ERROR) :  D3DRTYPE_SURFACE

    I know this is coming from the BitmapFont instance because if i remove “MyFont.drawString(….)” from my draw routine, I can switch (reset) from fullscreen to windowed without the exception firing.

    Any help would be greatly appreciated,

    Matt Moore

    [In addition to the SpriteBatch, there are also the font textures that need to be disposed of:

    Dictionary<int, Texture2D> m_dictBitmapID2Texture;

    I’ll fix this for the next release (by adding a Dispose method), but in the meantime you can add the following to your BitmapFont.Dispose:

    m_sb.Dispose();
    m_sb = null;
    foreach (KeyValuePair<int,Texture2D> kv in m_dictBitmapID2Texture)
       kv.Value.Dispose();
    m_dictBitmapID2Texture = null;

    After that, you should be ready to Reset. Let me know if you have any further problems and thanks for pointing it out!

    -GaryKac]

  11. Stuart says:

    regarding bitmap fonts, before finding this post I actually wrote a a very basic windows tool and XNA game object which allows one to drop/set and forget text onto a window, if anyone is interested it can be found on http://www.stuangel.com under the XNA link, I have also included a full tutorial on setting it up and a 4 line modification to a standard application to display text.

    Best regards

    Stu

  12. Matt Moore says:

    Still getting the surface error. I’m not sure what else needs disposing.

    Just to make sure i have:

    //handlers for device events
               device.DeviceLost += delegate { this.UnloadResources(); };
               device.DeviceReset += delegate { this.LoadResources(device); };

    Then:

    private void LoadResources(GraphicsDevice device)
           {
               //set anisotropic filter
               InitAnisotropy();
               debugFont.Reset(device);
           }

    private void UnloadResources()
           {
               debugFont.Dispose();          
           }

    Is this correct?

    [I don’t see any problems with what you’ve posted.  Can you create a small example project that exhibits the problem and send it to me? I suspect something else is going on but I can’t tell from the snippets.

    -GaryKac]

  13. Johan Hiemstra says:

    Hi,

    Thanks for sharing this! I really like the custom glyph option because it allows me to create my own custom ‘Photoshopped’ fonts instead of creating a separate bitmap for words like Game Over and Score 🙂

    I’ve been using it for a couple of days now and everything worked fine. I just tried to ‘publish’ my 2d shooter and I got an filenotfound exception. After doing some digging (I’m new to C# express)  I found that the .xml file is not copied to directory:
    shoo..tion_05bd4a2781ef8435_0001.0000_9c1bafe256fc38bb
    but is copied to:
    shoo…exe_05bd4a2781ef8435_0001.0000_none_4341aed75d4629b4

    When I copy the XML file from the exe to the tion directory it manually after installing the published version, it works fine. I have the xml and png file set to “Content” and “Copy always”. The other images in the game, with the same settings, show up in both directories.

    I’m guessing I’m just doing something very wrong, but I noticed some comments about the filepath in your other topic, so I was hoping you could clear this up, or maybe even, if appropriate, change the class to avoid this.

    Thanks again!

    [I don’t do anything magical with the files – I just expect them to be copied to the correct location (and to be given a path to that location). If they’re not being copied, then there must be something screwy with the copy. However, it doesn’t sound like you’re doing anything wrong.

    One suggestion I have is to create a new project, add the art assets and then make sure that they’re being copied over correctly. If they copy properly in the new project, then add all your source code and replace your old project with new one.

    Yes, this technically shouldn’t do anything, but I needed to do this once to “fix” a truly unfathomable problem I was encountering a week or so ago.

    If you’re still having problems with the “new project” version, then let me know.

    -GaryKac]

  14. Matt Moore says:

    Hey thanks for your help with my “problem.” Turns out that it was bad drivers screwing it up. Love the bitmap font generator.  Thanks a bunch.

    [I’m glad that you got it working. -GaryKac]

  15. Matt Moore says:

    Oh and one more thing.  If you don’t put the font files in a seperate directory, the class looks for the font file name in the “c:/: drive root instead of the root in the “bin/debug” folder.

    [You’re right. It will find the XML file, but will look in the wrong directory for the PNG image files. I’ll include a fix in this weekend’s release. Thanks!

    -Gary]

  16. JulioZou says:

    《XNA高级编程:Xbox 360和Windows》第四章第四小节:更多辅助类