The Font Class

We are going to use bitmap fonts to render arbitrary (ASCII) text. We already discussed how this works on a high level, so let's look at the code in Listing 9-4.

Listing 9-4. Font.java, a Bitmap Font-Rendering Class package com.badlogic.androidgames.framework.gl;

public class Font {

public final Texture texture; public final int glyphWidth; public final int glyphHeight;

public final TextureRegion[] glyphs = new TextureRegion[96];

The class stores the texture containg the font's glyph, the width and height of a single glyph, and an array of TextureRegions—one for each glyph. The first element in the array holds the region for the space glyph, the next one holds the region for the exclamation mark glyph, and so on. In other words, the first element corresponds to the ASCII character with the code 32, and the last element corresponds to the ASCII character with the code 127.

public Font(Texture texture, int offsetX, int offsetY, int glyphsPerRow, int glyphWidth, int glyphHeight) { this.texture = texture; this.glyphWidth = glyphWidth; this.glyphHeight = glyphHeight; int x = offsetX; int y = offsetY; for(int i = 0; i < 96; i++) {

glyphs[i] = new TextureRegion(texture, x, y, glyphWidth, glyphHeight); x += glyphWidth;

if(x == offsetX + glyphsPerRow * glyphWidth) { x = offsetX; y += glyphHeight;

In the constructor we store the configuration of the bitmap font and generate the glyph regions. The offsetX and offsetY parameters specify the top-left corner of the bitmap font area in the texture. In our texture atlas, that's the pixel at (224,0). The parameter glyphsPerRow tells us how many glyphs there are per row, and the parameters glyphWidth and glyphHeight specify the size of a single glyph. Since we use a fixed-width bitmap font, that size is the same for all glyphs. The glyphWidth is also the value by which we will advance when rendering multiple glyphs.

public void drawText(SpriteBatcher batcher, String text, float x, float y) { int len = text.length(); for(int i = 0; i < len; i++) { int c = text.charAt(i) - ' '; if(c < 0 || c > glyphs.length - 1) continue;

TextureRegion glyph = glyphs[c];

batcher.drawSprite(x, y, glyphWidth, glyphHeight, glyph); x += glyphWidth;

The drawText() method takes a SpriteBatcher instance, a line of text, and the x and y positions to start drawing the text at. The x- and y-coordinates specify the center of the first glyph. All we do is get the index for each character in the string, check whether we have a glyph for it, and if so, render it via the SpriteBatcher. We then increment the x-coordinate by the glyphWidth so we can start rendering the next character in the string.

You might wonder why we don't need to bind the texture containing the glyphs. We assume that this is done before a call to drawText(). The reason is that the text rendering might be part of a batch, in which case the texture must already be bound.

Why unnecessarily bind it again in the drawText() method? Remember, OpenGL ES loves nothing more than minimal state changes.

Of course, we can only handle fixed-width fonts with this class. If we want to support more general fonts, we also need to have information about the advance of each character. One solution would be to use kerning as described in the section "Handling Text with Bitmap Fonts". We are happy with our simple solution, though.

0 0

Post a comment