Saturday, February 15, 2014

Libgdx - Generate Bitmap Fonts for Any Screen Size With Minimal Loading Time.

UPDATE: I got some requests, so I created a github repo to make it easy to include this functionality into your project.  This the best way to use this code.

https://github.com/jrenner/gdx-smart-font


This post will show you how to use the FreeTypeFontGenerator (a libgdx extension) and the BitmapFontWriter (included in gdx-tools) to dynamically generate your bitmap font to suit the screen size of the device the app is running on.  We will also optimize the process so that the fonts are only generated if there is no previously generated version found.

FreeTypeFontGenerator is not part of the core libgdx package (not in gdx.jar), to learn how to include it in your project, or use it in general, see this page on the wiki.

BitmapFontWriter is also not part of libgdx core.  It is located in the gdx-tools.jar.  Fortunately, it has little dependencies, which means you can just copy/paste the code of the BitmapFontWriter class directly into your project as a single file, and get it working with little alterations.

Once you get those two things setup, you are ready to go.  Below is the code you need to accomplish font generation/loading.

We get three main benefits from this code:
#1 No need to pre-render font bitmaps using Hiero or some other tool

#2 Fonts are perfectly (more-or-less) sized in proportion to whatever screen size the app is launched with.  Screen-size changes in between launch are also handled. (For mid-game resizing, you would have to do some more work)

#3 By saving the generated fonts to file, we can load from file in subsequent startups where the screen size has not changed (On Android, it should never change).  In my case, this cuts down the loading time for fonts dramatically, make the app start up much snappier.

In my case, where I generate 4 fonts, generating fonts took 3765ms, while loading the pre-generated fonts only took 325ms.  That's more than 3 seconds shaved off of app startup time!

In the images below, notice how despite the different window sizes, the fonts retain the same proportion.  The same effect will occur on Android screens.


1280x720

800x480



First, let's take a look at the code generating the fonts:


Now, let's see how we save the generated fonts to file.  These methods could be directly copied and pasted into your project without alteration.

22 comments:

  1. I don't quite get one single detail: suppose I'm using a FitViewport in scene2d and fixed world coordinates, say 900x1600. Does this code still work? I'd like to use world units for my font size, but I suspect this code would scale the font twice: once in lines 24-42 of the first code block, and the second time is done by gdx itself during scene rendering... am I wrong? Should I replace Gdx.graphics.getWidth() at line 24 with my world width (900)?

    ReplyDelete
  2. Here is a simple way if you wanted your fnt file to fit on all device you just need to scale it like that

    fnt.setScale(.9f,.9f);

    ReplyDelete
    Replies
    1. You can do this, but it tends to look rather bad, especially if you scale up (> 1f)

      Delete
  3. I try change your code to

    FileHandle exoFile = Gdx.files.internal("assets/LiberationMono-Regular.ttf");

    ReplyDelete
    Replies
    1. and I can't use text as korean in Label.

      Delete
    2. To use Korean or other special characters you need to change the DefaultCharacters setting used when generating the font

      Delete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Hi, thanks for the code, it's really useful. However, there's a bug in your SmartFontGenerator class on github inside the createFont method, you don't use the calculated ratio therefore the font won't scale.

    The code should be:

    if (!loaded || forceGeneration) {
    forceGeneration = false;
    float width = Gdx.graphics.getWidth();
    float ratio = width / referenceScreenWidth; // use 1920x1280 as baseline, arbitrary
    float baseSize = 28f; // for 28 sized fonts at baseline width above

    int size = (int) (fontSize * ratio);

    // store screen width for detecting screen size change
    // on later startups, which will require font regeneration
    fontPrefs.putInteger("display-width", Gdx.graphics.getWidth());
    fontPrefs.putInteger("display-height", Gdx.graphics.getHeight());
    fontPrefs.flush();

    font = generateFontWriteFiles(fontName, fontFile, size, pageSize, pageSize);
    }

    ReplyDelete
  6. Hi Jon. Nice work. Can you help me in importing other language ttf and displaying the same. For ex: Hindi. Better i can say, can you go through this link and give me a fair idea as how to have it in libgdx.
    http://javatechig.com/android/how-to-use-hindi-font-in-android-application

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. Do you know, how to render Hindi text in libgdx. For example प्रकार ?

      Delete
  7. I am using libgdx and same code mention above. Its perfectly working for Android and Desktop. But this given compile error in GWT compile when building HTML project.
    [ERROR] Line 264: No source code is available for type com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; did you forget to inherit a required module?
    [ERROR] Line 265: No source code is available for type com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFontParameter; did you forget to inherit a required module?

    Please give me some suggestions so that i reused the same code in HTML

    ReplyDelete
    Replies
    1. As far as i know, you cannot use FreeTypeFontGenerator in HTML. It will show a warning when you are creating LIBGDX project itself. You should create the font file (.fnt) by using heiro or other tools and load that.

      Delete
  8. How to render Hindi text in libgdx.

    ReplyDelete
  9. Hi Arvind. We tried so many approaches to render Hindi text, just to fail. So we took a work around of loading texts as images. You can render Hindi text in native Android and iOS easily and can take a screenshot of them. For all the static texts, we took the screenshots, stored them as images and embedded in the apk or the ipa. For runtime generating texts, we took screenshots at runtime, get the data as bitmap and convert it into pixmap and render them in the LibGDX view. It works like a charm !
    Happy Coding !

    ReplyDelete
  10. Dafont.com is a site where you can download a ton of free fonts. You can search for a specific typeface, or search by the type of lettering you want, whether it’s serif or sans serif, hand lettered or grunge style. You can also put in your own phrase to see how it looks in a particular font. A lot of these fonts are very decorative and many are handdrawn, so it’s not always the best place to search for body text fonts. Each selection also tells you whether your download is free for personal or commercial use. The download is easy – you get a zip file with the font file inside. Unzip, install, and you’re ready to go.

    ReplyDelete
  11. Dafont.com is a site where you can download a ton of free fonts. You can search for a specific typeface, or search by the type of lettering you want, whether it’s serif or sans serif, hand lettered or grunge style. You can also put in your own phrase to see how it looks in a particular font. A lot of these fonts are very decorative and many are handdrawn, so it’s not always the best place to search for body text fonts. Each selection also tells you whether your download is free for personal or commercial use. The download is easy – you get a zip file with the font file inside. Unzip, install, and you’re ready to go.

    ReplyDelete
  12. Dafont.com is a site where you can download a ton of free fonts. You can search for a specific typeface, or search by the type of lettering you want, whether it’s serif or sans serif, hand lettered or grunge style. You can also put in your own phrase to see how it looks in a particular font. A lot of these fonts are very decorative and many are handdrawn, so it’s not always the best place to search for body text fonts. Each selection also tells you whether your download is free for personal or commercial use. The download is easy – you get a zip file with the font file inside. Unzip, install, and you’re ready to go.

    ReplyDelete
  13. Dafont.com is a site where you can download a ton of free fonts. You can search for a specific typeface, or search by the type of lettering you want, whether it’s serif or sans serif, hand lettered or grunge style. You can also put in your own phrase to see how it looks in a particular font. A lot of these fonts are very decorative and many are handdrawn, so it’s not always the best place to search for body text fonts. Each selection also tells you whether your download is free for personal or commercial use. The download is easy – you get a zip file with the font file inside. Unzip, install, and you’re ready to go.

    ReplyDelete
  14. Dafont.com is a site where you can download a ton of free fonts. You can search for a specific typeface, or search by the type of lettering you want, whether it’s serif or sans serif, hand lettered or grunge style. You can also put in your own phrase to see how it looks in a particular font. A lot of these fonts are very decorative and many are handdrawn, so it’s not always the best place to search for body text fonts. Each selection also tells you whether your download is free for personal or commercial use. The download is easy – you get a zip file with the font file inside. Unzip, install, and you’re ready to go.

    ReplyDelete
  15. Hi, i absolutely got tons of value from your post. Please i have 2 quick questions.
    1. What is the number of plugins every blogger shouldn’t exceed? I currently have about 18 installed, would you consider that number outrageous. Please could you also check out my site and offer me a
    2. Your font is really beautiful. would you suggest plugins that would give me beautiful fonts just like yours?
    Finally, would you spare a few seconds to check this site and offer me your candid advice http://www.samozoani.com

    ReplyDelete