/gl3font

Generating signed-distance maps for font atlases, and rendering them with hx-ogl.

Primary LanguageC++

rendering example

Simple, high quality font rendering for opengl.

Whilst the API in this library is specific to Haxe and the hx-ogl API, the ttfcompile tool would be easily used in any suitable environment where we haxe programmable shaders, so any stage3d (flash), or other opengl/directx environment.

Based upon Valve's siggraph paper: http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf

ttfcompile:

This small c++ tool takes a font file (compatible with freetype2), eg TrueType .ttf, and produces a texture atlas .png of a given set of characters (By default all ISO-1 Latin + ISO-7 Greek characters) as a signed distance field, together with a .dat file describing necessary information to make use of the atlas.

Support for full unicode.

./ttfcompile font size gap search-radius output-size [-chars=char-set] [-o=output-name]
  • font : The font file (eg: /usr/share/fonts/truetype/freefont/FreeSans.ttf)
  • size : Pixel size for font when rendering an intial atlas of characters. Should aim for some large value like 250 so that we have a sufficiently high quality atlas to compute the distance field from.
  • gap : Pixel gap between characters in initial atlas, a value of 3 seems to give a good tradeoff between efficiency in terms of how large the output image must be to get good quality, whilst preventing adjacent characters intefering in the distance field.
  • search-radius : Pixel radius in the initial high quality atlas for performing brute-force search of nearest boundary, needs to scale with the pixel font size, a value of 40 for a font size of 250 seems to work well.
  • output-size : Pixel size for the dimensions of the output distance field (Actual output may likely have one dimension shorter, output is not generally an exact square).
  • char-set : Set of unicode characters to use for the atlast, by default all of the ISO-1 latin + ISO-7 greek code pages.
  • output-name : Name for output files (and location), output files written as output-name.png and output-name.dat. By default the given font file name/location is used for output-name.

A set of fonts are already pregenerated in the free and dejavu subdirectories generated by the commands listed in the ttfcompile/given bash script.

The ttfcompile tool depends on libraries: libpng, png++, icu, freetype2 and requires c++11 compatible compiler.

The output .dat file has the following, simple (binary) format:

character-count : uint32  // number of characters in the font atlas
line-height     : float   // height between baselines for font rendering.
line-ascender   : float   // (not-guaranteed) height from the base line to
                             highest point in the font.
line-descender  : float   // (not-guaranteed) height from the base line to
                             lowest point in the font.
{ character-code : uint32   // Unicode code point associated with atlas index.
  horiz-advance  : float    // How much to advance pen-position after
                               rendering this character.
  offset-left    : float    // horizontal offset to pen-position when
                               rendering this character.
  offset-top     : float    // vertical offset to pen-position when
                               rendering this character.
  char-width     : float    // width of character
  char-height    : float    // height of character
  atlas-u        : float    // normalised tex-coordinate in atlas
                               for this character.
  atlas-v        : float    // normalised tex-coordinate in atlas
                               for this character.
  atlas-w        : float    // normalised width in atlas for character.
  atlas-h        : float    // normalised height in atlas for character.
}  <-- repeated character-count times.
{ horiz-kerning  : float    // horizontal offset to be applied before rendering
                               a character based on previously rendered char.
  repeats        : uint32   // number of times this kerning value is repeated in
                               the matrix.
}  <-- repeated as many times as is necessary to enumerate
      character-count * character-count entries.

All values are based on the font having a pixel size of 1px regardless of input parameters to ttfcompile.

example, the kerning matrix:

[[ 0, 0, 0, 1 ]
 [-1, 1, 1, 0 ]
 [ 0, 0, 0, 0 ]
 [ 1, 1, 1, 1 ]]

would be encoded in the .dat file as

0:ft, 3:u32, 1:ft, 1:u32, -1:ft, 1:u32, 1:ft, 2:u32, 0:ft, 5:u32, 1:ft, 4:u32

Can check the free, and dejavu subdirectories for example outputs.

Alternative usage.

./ttfcompile -transform input.png search-radius output-size [-o=output-name]

To convert an input greyscale png (high resolution) to a distance field as per ttf transformation.

No data output is made (obviously).

gl3font API:

Simple API for rendering said fonts generated with ttfcompile using ogl, all types included with import gl3font.Font;

Depends upon ogl and hxformat.

Font class used to load and parse font files from ttfcompile.

class Font {
    // Load font files, create opengl texture (must have a context!)
    // Can pass null for .dat path if wanting to simply load
    // the distance map to a texture for use.
    function new(path_to_dat:Null<String>, path_to_png:String);

    // ID for the opengl texture generated.
    var texture : GLuint;

    // Information from .dat file parsed.
    var info : FontInfo;

    // Destroy GL state, can't use font following this call.
    function destroy();
}

Structure storing font metric information from .dat file.

class FontInfo {
    // Map from character's unicode point value, to index in the atlas/FontInfo structure.
    var idmap : Map<Int,Int>;

    // Global font metrics
    var height : Float;
    var ascender : Float;
    var descender : Float;

    // Kerning matrix, [prev][curr] : Float for horizontal offset before rendering 'curr' after 'prev'
    var kerning : Array<Array<Float>>;

    // Metrics for each character in the font
    var metrics : Array<Metric>;
}

Per character metrics from .dat file.

class Metric {
    // Horizontal offset after rendering character.
    var advance : Float;

    // Horizontal and vertical offsets for rendering character.
    var left : Float;
    var top : Float;

    // Character size
    var width : Float;
    var height : Float;

    // Character texture rectangle in atlas png
    var u : Float;
    var v : Float;
    var w : Float;
    var h : Float;
}

Rendering engine for gl3font fonts.

class FontRenderer {

    function new();

    // Set transformation matrix for rendering font to the screen.
    function setTransform(mat:Mat4) : FontRenderer;

    // Set font colour for rendering
    function setColour(colour:Vec4) : FontRenderer;

    // Begin rendering fonts (Selects gl program, enables vertex attrib arrays)
    function begin() : FontRenderer;

    // End rendering of fonts (disables vertex attrib arrays)
    function end() : FontRenderer;

    // Render a string, must be called being begin() and end()
    function render(string:StringBuffer) : FontRenderer;

    // Render arbitrary vertex data (with distance field texture)
    function renderRaw(texture:GLuint, vertexBuffer:GLuint) : FontRenderer;

    // Destroy GL state, can't use renderer following this call.
    function destroy();
}

GL3Font 'string', string data is buffered for efficient rendering.

class StringBuffer {

    // Create string buffer with initial space for 'size' characters
    // and with vertex buffer set for either static, or dynamic drawing.
    // (Strings that frequently change should be dynamic).
    function new(font:Font, ?size:Int=1, ?staticDraw:Bool=false);

    // Font in use for string, can be changed at any 'reasonable' time.
    // i.e. changing font, after setting text, but before rencering has no effect
    // on that rendered text.
    var font:Font;

    // Set StringBuffer to render the given string, using given alignment.
    // Multiline strings (delimited by \n) permitted.
    //
    // Returns Vec4 for text bounds (x,y,width,height)
    function set(string:String, ?align:FontAlign=AlignLeft) : Vec4;

    // Destroy GL state, can't use string buffer following this call.
    function destroy();
}

Possible alignment modes for rendering font.

enum FontAlign {
    AlignLeft;   // Text drawn starting with first baseline at y=0, rendering each line to the right of origin.
    AlignRight;  // Text drawn starting with first baseline at y=0, rendering each line to the left of origin.
    AlignCentre; // Text drawn starting with first baseline at y=0, rendering each line centered on x=0.

    // Justified varients of the above. Each line has spacing artificially scaled up so that every line covers
    // the same horizontal space.
    AlignLeftJustified;
    AlignRightJustified;
    AlignCentreJustified;
}

samples/:

Basic usage example (depends upon glfw3) demonstrating basic text rendering, using suitable transforms to render text centered at mouse cursor with given pixel size and rotation on 2d screen.