Note: The tutorial, the discussed features and methods are referring to the latest MT4j version from the Google Code SVN respository and may not be available/supported in the stable release package from the download area.

Contents

Introduction

This article discusses the font system and text rendering possibilities in MT4j and how to use them.

Goals

  • learn how to load different fonts
  • understand the difference between vector and bitmap fonts
  • learn how to render text using MT4j components

Fonts

Loading and rendering fonts and text in a 3D environment (as in MT4j) is fundamentally different from a 2D environment. In a 2D environment, the font characters' pixels can be directly rendered onto the screen while when using a 3D graphics pipeline, other strategies have to be applied. There are basically two different approaches, each having different pros and cons: Vector Fonts and Bitmap Fonts.

Vector / Geometric Fonts

Vector font characters are rendered using many small geometric primitives like triangles and lines.

Advantages Disadvantages
  • text can be moved, scaled, rotated while the text stays sharp without getting "fuzzy"
  • big font sizes dont consume more memory than small font sizes (-> geometric fonts are better suited for big font sizes)
  • text can be modified (extruded, morphed, sheared, etc) by modifiying the character's geometry
  • text characters could be integrated with collision detection (using a phyics engine for example) or OpenGL Lightning
  • consumes fair amount of memory for storing the geometric information
  • fairly long loading time for the geometry to be created and stored -> best done at application start
  • rendering long texts can be taxing on performance
  • small font sizes may show visual artifacts due to the way anti-aliasing is done

Bitmap / Texture Fonts

An image of each font character is created and mapped onto a rectangle as a texture.

Advantages Disadvantages
  • very good performance as only a rectangle has to be rendered for each character
  • good readability at small font sizes, crisp text with anti-aliasing turned off
  • if the text is scaled, rotated it will become blurry/fuzzy or aliased
  • big font sizes consume fair amount of texture memory

Summary

If we want to render a component containing text, we should first think about how the text will be used to decide whether we want to go with a vector or a bitmap font.
As a short guideline to decide which fonts to use:

  • if we need small to medium sized text
  • if the text is mostly stationary
  • if the text is pretty long
    => use Bitmap Fonts
  • if we need medium to big font sizes
  • if the text needs to be scaled/rotated dynamically and seamlessly
    => use Vector Fonts

If in doubt just switch between vector and bitmap fonts and check which one performs better.

Loading Fonts

Fonts in MT4j can be loaded using the FontManager singleton class and its createFont(..) method. The FontManager contains different font factory classes which are responsible for loading the desired fonts. Which font factory is used to load the font depends on the font's file suffix. The FontManager also contains an internal cache that caches fonts with the same name, color, size and anti-aliasing setting so that calling FontManger.getInstance().createFont(pa, "arial.ttf", 24); two times in our code will return the already cached font the second time. This will reduce the loading time significantly. So for speed and memory reasons it is advisable to re-use the same fonts where possible. It might also be advisable to load the fonts at the start of the application rather than at runtime to avoid delays.
At the moment MT4j supports loading of following fonts:

  • All system fonts which are found by Java (as bitmap fonts)
  • True Type fonts (.ttf) from file (as vector or bitmap fonts, vector by default)
  • Scalable Vector Graphics (.svg) font files (as vector fonts)

When loading a font, we can specify the font, font size, color and anti-aliasing. (anti-aliasing setting is only available in a version greater than 0.9)

Loading Vector fonts

A Vector font will be created if a font is loaded from a TTF font file with the suffix ".ttf. Also, SVG (Scalable Vector Graphics) font files with the suffix ".svg" can be loaded as vector fonts.

Example:

FontManager.getInstance().createFont(mtApplication, "arial.ttf", 24);

This will try to load the "arial.ttf" font contained in the "./data" or "./src/data" directory as a vector font. The font size will be 24, the color will be black and anti-aliasing enabled by default.

You can also specify a different color:

IFont font = FontManager.getInstance().createFont(mtApplication, "somefont.svg", 
                                50,    //Font size
                                new MTColor(255,255,255),  //Font fill color
                                new MTColor(255,255,255));  //Font outline color

This will create a white vector font from an svg font file.

Loading Bitmap Fonts

Bitmap fonts can be created by using the installed system fonts which doesent require us to provide an extra font file to load from. Thus, to load a bitmap font, we just specify the font name without a file suffix. A list of available system fonts can be accessed by the method PFont.list(). For the MT4j application to be portable and runnable across different platforms and operating systems we need to make sure that the desired font is supported on all these systems!

This example code prints out all available system fonts:

         for (String fontName : PFont.list()) {
                        System.out.println(fontName);
                }


This example code will load the "SansSerif" system font as a black Bitmap font with fontsize 12 and anti-aliasing turned off (a.a. setting only available in MT4j version greater than 0.9). Bitmap fonts can of course also be loaded with a different color but in contrast to vector fonts, bitmap fonts dont support the use of a different outline color.

IFont font = FontManager.getInstance().createFont(mtApplication, "SansSerif", 12, false);

TIP: We can force the use of a bitmap font factory instead of the default vector font factory for font creation from a .ttf True Type Font file. This allows to load bitmap fonts from a .ttf file packaged alongside the application, independent of the fonts installed on the target system. To accomplish this we just register a bitmap font factory for the suffix ".ttf":

FontManager.getInstance().registerFontFactory(".ttf", new BitmapFontFactory());

Anti-Aliasing

Per default, vector and bitmap fonts will be drawn anti-aliased to look smoother.
The anti-aliasing in vector fonts is achieved by drawing the outlines of each character using anti-aliased lines. While this often looks nice, it produces slightly thicker polygons that make the font look bold. At small font sizes the lines may produce some artifacts. But switching off anti-aliasing for vector fonts is only recommended if in turn OpenGL multi-sampling with a sampling rate of 4 or better 8 is chosen to fight the aliasing effects.

The anti-aliasing for bitmap fonts is done by java internally and then rendered into an image. As vector fonts, anti-aliased bitmap fonts look nice at medium or larger font sizes. At small font sizes the anti-aliasing may make the font look too soft or blurry. Here it makes sense to switch off anti-aliasing for a crisper look. Again, some experimentation what setting looks best is in order.

Text components

Now that we know how to load a font we want to use them to render texts or labels. At the moment, MT4j provides two components capable of rendering text.

Text Area

The most used text component is probably the MTTextArea class. It allows to render multiple lines of text using different wrapping modes. The text area's constructor takes a loaded font as an argument.
Following wrap modes are supported:

  • Wrap mode:

=> A line break will be added if the width of a text line exceeds the width of the text area. The text is also clipped to the dimensions of the text area if the text exceeds the height of the text area.

  • Expand mode:

=> The text area's size is fitted to the text of the text area. The dimensions will shrink or expand dynamically when characters are added or removed.

Which mode will be used depends on which constructor is used to instantiate the MTTextArea. If we use a constructor which specifies a fixed width and height of the textarea the clipping and word wrapping will be enabled automatically. If no dimensions are specified, the expand mode is used.
Example:

MTTextArea texta = new MTTextArea(0,0, 200,600, font , mtApplication);

This will create a text area with 200 units width and 600 units height. Word wrapping and clipping will be enabled.

Relevant methods:


Using the constructor without any dimensions, we get the expanding mode behaviour:

MTTextArea text = new MTTextArea(mtApplication, FontManager.getInstance().createFont(mtApplication, "SansSerif", 18));

This creates a text area at the origin, with a minimum size that will expand if font characters are added.

Text Field

The MTTextField class allows to display a single line of text. It is useful for labels or user input text fields. Line breaks are irgnored and the text is clipped to the dimensions of the text field. If the text exceeds the width of the field, the text is scrolled to the left.
Example:

         MTTextField field = new MTTextField(50, 50, 150, 30, FontManager.getInstance().createFont(mtApplication, "SansSerif", 18), mtApplication);
                field.setText("ABCDEFGHIJKLMNOPQRSTUV\nWXYZ");
                getCanvas().addChild(field);


Powered by MediaWiki contact