Saturday, September 21, 2013

LibGDX Tutorial 7: TextureRegions and Custom Fonts

Objectives
  • What are TextureRegions
  • How to use the BMFont program
  • How to use the custom fonts created by BMFont in libGDX

What are TextureRegions
An image might have many subimages. This is an image with four subimages.

This is shown in GIMP window:

One way to use such images in a ligGDX application is to load into Texture, and then create TextureRegions and load a region from texture like
boxes = new Texture(Gdx.files.internal("boxes.png")); //** loading boxes **//
box1 = new TextureRegion(boxes,0,0,180,320);
box2 = new TextureRegion(boxes,200,0,480-200,320);
box3 = new TextureRegion(boxes,0,330,127,511-330);
box4 = new TextureRegion(boxes,180,325,511-180,511-320);


I calculated the locations and widths, and heights using the GIMP graphics program, and then using them in the four TextureRegion constructors. As we will see there are better methods rather than writing the coordinates ourselves.

The BMFont program
This program can be obtained at http://www.angelcode.com/products/bmfont/. This is a Windows program. The libGDX website has also another program Hiero (which is a JAR archive) and is explained at http://code.google.com/p/libgdx/wiki/Hiero.

Opening the BMFont program after installation gives


The Options menu gives the various options

We use Font Settings option to select our font, Export Options to select how to export, Visualize to see what we are exporting and finally we can save the file using Save bitmap font as ...

In the Font Setting we select a font

The font selected in the example is Comic Sans MS, with a size of 48 pixels. After selecting OK, next we go to Export Options.

I selected a size of 512 by 512. Select bit depth of 32 bits. I used the Preset Black text with alpha. Finally select PNG for image format in Textures. Leave the Text option for Font descriptor.

After selecting OK,I select these 65 characters (highlightened). Select by clicking on character.

Next I use the Visualize option


This shows the size is too big. I settled on 256 by 256 and I entered that in the Font Settings. Next I visualized


This is now OK. Thus the Option for saving can be selected. If the saved name is CustomFont we will get these two files:

  

I changed the image file name to CustomFont.png (as I only have one image) and opened the text file and changed the name of the file (in line 3):

Now these two files can be moved to the asset folder in the Eclipse project for the project, that is after creating the project files.

Setup and using the font
Create the project files.



Import the projects into Eclipse. After placing the file we can use the font.
fontTexture = new Texture(Gdx.files.internal("CustomFont.png"));
font=BitmapFont(Gdx.files.internal("CustomFont.fnt"), new TextureRegion(fontTexture), false);

MyCustomFont.java
package com.tutorials.mycustomfont;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class MyCustomFont implements ApplicationListener {
    private OrthographicCamera camera;
    private SpriteBatch batch;
    private Texture fontTexture;
    private Texture boxes; //** all 4 boxes **//
    private TextureRegion box1; //** box 1 **//
    private TextureRegion box2; //** box 2 **//
    private TextureRegion box3; //** box 3 **//
    private TextureRegion box4; //** box 4 **//
    private BitmapFont font; //** font **//
    private int pos1, pos2, pos3, pos4; //** positions boxes are displayed **//
   
    @Override
    public void create() {      
        camera = new OrthographicCamera();
        camera.setToOrtho(false, 800, 800);
      
        batch = new SpriteBatch();
      
        fontTexture = new Texture(Gdx.files.internal("CustomFont.png")); //** loading font **//
        //fontTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear); //** setting its scaling behavior **//
      
        boxes = new Texture(Gdx.files.internal("boxes.png")); //** loading boxes **//
        box1 = new TextureRegion(boxes,0,0,180,320);
        box2 = new TextureRegion(boxes,200,0,480-200,320);
        box3 = new TextureRegion(boxes,0,330,127,511-330);
        box4 = new TextureRegion(boxes,180,325,511-180,511-320);
        // ** Calculate the positions once so program will not have to recalculate each time in render **//
        pos1 = 50; // ** first box will be displayed at x = 0
        pos2 = pos1 + box1.getRegionWidth()+10; //** 2nd box x-position **//
        pos3 = 50; //pos2 + box2.getRegionWidth()+10; //** 3rd box x-position **//
        pos4 = pos3 + box3.getRegionWidth()+10; //** 4th box x-position **//
      
        font = new BitmapFont(Gdx.files.internal("CustomFont.fnt"), new TextureRegion(fontTexture), false);
        font.setColor(0,0,1,1); //** Blue text **//
    }

    @Override
    public void dispose() {
        batch.dispose();
        fontTexture.dispose();
        boxes.dispose();
        font.dispose();
    }

    @Override
    public void render() {      
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
      
        batch.setProjectionMatrix(camera.combined);
        batch.begin();
        font.draw(batch, "HELLO WORLD!", 50, 700);
        font.draw(batch, "BELOW ARE FOUR BOXES:", 100, 650);
        batch.draw(box1, pos1, 0);
        batch.draw(box2, pos2, 0);
        batch.draw(box3, pos3, 350);
        batch.draw(box4, pos4, 350);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}


This is the program output:









1 comment: