Font metrics changes

For bitmap fonts, padding can be added when the bitmap font is created to give more space around the glyphs for effects like a glow or drop shadow. BitmapFont has so far ignored padding, as reported in #3074. This means the font metrics change depending on the padding used, which makes it difficult to draw text where you want it. This PR has now been fixed, so the metrics are the same no matter how much padding is used around the glyphs.

Font metrics

Unfortunately this means that if you had been using a font that used padding, all of your carefully placed text may change size or position. You can go and fix this up everywhere, but for existing apps it is likely easier to just use this code to go back to the old behavior:

/** Adjusts the font data metrics to not take padding into account. */
static private void includePaddingInMetrics (BitmapFontData fontData) {
	float padY = fontData.padTop + fontData.padBottom;
	fontData.xHeight += padY;
	fontData.capHeight += padY;
	fontData.ascent -= padY;
	fontData.descent -= fontData.padBottom;
	fontData.padTop = 0;
	fontData.padLeft = 0;
	fontData.padBottom = 0;
	fontData.padRight = 0;
}

libGDX 1.5.6 Released

libGDX 1.5.6

Time for a new release. Just because Nate couldn’t stop refactoring. Welp, that, and there’s a new RoboVM release! More on that below.

The CHANGELOG:

[1.5.6]
- API Change: Refactored Window. https://github.com/libgdx/libgdx/commit/7d372b3c67d4fcfe4e82546b0ad6891d14d03242
- Added VertexBufferObjectWithVAO, see https://github.com/libgdx/libgdx/pull/2527
- API Change: Removed Mesh.create(...), use MeshBuilder instead
- API Change: BitmapFontData, BitmapFont, and BitmapFontCache have been refactored. http://www.badlogicgames.com/wordpress/?p=3658
- FreeTypeFontGenerator can now render glyphs on the fly.
- Attribute now implements Comparable, custom attributes might need to be updated, see: https://github.com/libgdx/libgdx/wiki/Material-and-environment#custom-attributes
- API Change: Removed (previously deprecated) GLTexture#createTextureData/createGLHandle, Ray#getEndPoint(float), Color#tmp, Node#parent/children, VertexAttribute#Color(), Usage#Color, ModelBuilder#createFromMesh, BoundingBox#getCenter()/updateCorners()/getCorners(), Matrix4.tmp

Note: Make sure to update your RoboVM Eclipse plugin to 1.1.0! There’s now also a RoboVM IntelliJ IDEA plugin!

Let us know if you run into any issues. See this wiki article on how to update your libGDX project to the latest version. The current libGDX version is “1.5.6”, the current nightly version is “1.5.7-SNAPSHOT”, OR you can just check our versions page which details all the versions of dependencies as well.

What i’ve been up to (RoboVM 1.1 released, 50% off :D)

My day job for the past months has been working on RoboVM. I’ve been responsible for implementing the debugger, the IDEA plugin, fixing bugs here and there, and am currently involved in the documentation effort. Today, we released version 1.1, and that comes with a super huge feature: Interface Builder support!

Interface Builder is part of Xcode and allows Objective-C/Swift folks to design their iOS UIs visually and simply wire things up with code. We now support doing the same, and it’s very nifty. Check out this walk through of Interface Builder basics:

This is a really big productivity boost for RoboVM users. Interface Builder integration is free for everyone, including RoboVM users that only use the open-source core, until the 1st of May. So, if you feel curious about iOS development, install the RoboVM plugin for your preferred IDE, and give the tutorials on your documentation page a try. Would love to hear feedback!

Why am i telling you this? libGDX folks publishing to iOS use RoboVM under the hood. You don’t need to pay a single dime for that. The core of RoboVM is open-source and free as in beer, no strings attached. However, obviously we RoboVM folks need to put food on the table as well. So, if you want debugging and Interface Builder support, you have to subscribe for a license.

Doing a release is a lot of sweat and tears. Once you press the button, you loosen up a bit and feel really happy. We do share this feeling with our community through happy tweets and blog post. However, we can do better.

If you sign up for a Solo or Startup license until the 1st of May 2015, you get a 50% discount

Head over to the RoboVM release blog post to get more info.

Until then, happy coding!

BitmapFont refactoring

My friends! Let’s talk about font rendering. So far we’ve been using a relatively naive way of rendering in libgdx: for each character in the string, find the glyph, draw the glyph. This works fine for English and others, but not all. Some languages use different glyphs for the same character depending on where it appears in the word or sentence. As soon as we don’t have a one-to-one relationship between characters and glyphs, we can’t do proper rendering.

The solution for this is to transform the list of characters into a list of glyphs, then render the glyphs. The BitmapFontData, BitmapFont, and BitmapFontCache classes have been refactored to support doing that. Here’s how it works:

  1. GlyphLayout, a new class, is given a string of characters. It first breaks the strings into “runs”. A run is a string of characters all the same color and without newlines. The reason to break the text into runs is that each run can be “shaped” individually, which means to convert the characters into glyphs for display. When breaking the string into runs, GlyphLayout parses color markup tags (eg “thisIsWhite[red]thisIsRed”) and stores the color for each run.
  2. Next, the runs are shaped using a new BitmapFontData method, getGlyphs. This takes the characters for the run and generates both a list of glyphs and a list of positions for each glyph. The default implementation just looks up the glyph for the character as has always been done. A more complex implementation could use HarfBuzz or another lib to do the shaping.
  3. Next, the shaped runs are laid out. If wrapping is enabled and a run’s glyphs exceed the wrap width, then glyphs are split for line wrapping using another new BitmapFontData method, getWrapIndex. The run is ended, the remaining glyphs are moved to a new run on the next line, and the layout process repeats. Because BitmapFontData controls line wrapping, it can be customized for a particular langauge.
  4. At this point GlyphLayout is done. It stores the Array<GlyphRun> and provides a width and height which is the bounds of all the runs. Previously getting text bounds required all the work of laying out the glyphs, which then had to be repeated for drawing. With GlyphLayout, the work is only done once. Each GlyphRun has Array<Glyph> and a FloatArray for the positions.
  5. Next comes BitmapFontCache. This class now has an Array<GlyphLayout> and its job is to store the vertex data for rendering the glyphs in those GlyphLayouts.

Introducing GlyphLayout and the new way of rendering glyphs required some relatively small API changes. Sorry! Since breaking the API was unavoidable, we also made a few other breaking changes. It’s better to fix up a few API changes in one go than to have to do it every time you update libgdx.

Here are the changes that may affect you:

  • The BitmapFontCache setText, setMultilineText, setWrappedText, and similar addXxx methods are replaced by setText and addText. The same happened to the BitmapFont draw methods, which delegates to BitmapFontCache. There are fewer methods now and they have more features. These methods all return GlyphLayout instead of TextBounds.
  • BitmapFont.TextBounds and getBounds are done. Instead, give the string to GlyphLayout and get the bounds using its width and height fields. You can then draw the text by passing the same GlyphLayout to BitmapFont, which means the glyphs don’t have to be laid out twice like they used to.
  • BitmapFont.HAlignment is gone. Align is used instead.
  • Align has been moved to the utils package.
  • markupEnabled and setScale have been moved to BitmapFontData. These are really BitmapFontData settings, not per BitmapFont settings.
  • BitmapFont computeGlyphAdvancesAndPositions and computeVisibleGlyphs are gone. GlyphLayout can be used instead, which provides each glyph position.
  • BitmapFont has an Array<TextureRegion> rather than a TextureRegion[]. This makes it easier to add regions as needed.

Here’s a quick guide for moving to the new API:

// Old:
font.draw(batch, "meow", x, y);
font.drawMultiline(batch, "meow\nmeow", x, y);
font.drawWrapped(batch, "meow meow meow meow meow meow", x, y, width, HAlignment.RIGHT);

TextBounds bounds = font.getBounds("meow");
font.draw(batch, "meow", x + bounds.width / 3, y + bounds.height / 3);

// New:
font.draw(batch, "meow", x, y);
font.draw(batch, "meow\nmeow", x, y);
font.draw(batch, "meow meow meow meow meow meow", x, y, width, Align.right, true);

GlyphLayout layout = new GlyphLayout(); // Obviously stick this in a field to avoid allocation each frame.
layout.setText("meow");
font.draw(batch, layout, x + layout.width / 3, y + layout.height / 3);

Sorry for the trouble if you end up needing to change your code slightly, but this enables us to have proper font rendering in the future. HarfBuzz and FreeType can allow us to render text in any language, which is a big deal!

But wait, there’s more! Many languages don’t need glyph shaping – they can use a one-to-one mapping of characters to glyphs – but they have a different problem: they have way too many glyphs than we can hope to fit on a texture. There are only a few solutions for this, you need to render on the fly.

Rendering entire sentences to the atlas instead of individual glyphs is one approach, but this isn’t great for text input or text that changes a lot. Rendering glyphs on the fly, as they are encountered, is probably the best we can do. If the glyph atlas becomes filled, we can either add atlas pages (bad for draw calls) or empty the atlas texture and start over (fails if the screen contains more glyphs than can fit in a single page).

Rendering glyphs on the fly means using FreeType. We already have FreeTypeFontGenerator to generate a BitmapFont using FreeType, but now you can tell it to generate an “incremental” font. When the font is queried for a glyph that hasn’t been rendered yet, it renders it to the glyph atlas.

The red boxes at the top are the glyph atlas pages (purposefully made tiny for testing) and the text below is rendered using those glyphs. We can implement better packing (eg, a skyline variant) in the future, for now it uses PixmapPacker as it used to.

It will be interesting to see if this helps libgdx have better adoption in China, where currently cocos2d-x is widely used. Interestingly, cocos2d-x appears to use a “label” approach to font rendering where an entire sentence is rendered to the backing texture rather than individual glyphs.

If you’re interested in the changes for these features, you can check out PRs #2955 and #2973.