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: https://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
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=chars-set] [-charsfile=chars-file] [-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 like250
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 of3
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 of40
for a font size of250
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).chars-set
: Set of unicode characters to use for the atlast, by default all of the ISO-1 latin + ISO-7 greek code pages.chars-file
: Name of utf8-textfile that containschar-set
.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.
./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).
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;
}
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.