It's been a while since my last time posting in here: let's just say that the joys of fatherhood took away most of my free time, usually dedicated to side-projects and programming in general.
Now that in the family we all reached a somewhat stable schedule, I can resume this very good habit.
I want to start by writing about a very simple library about 3D text, but, unlike my latest post that was based on a new format creating geometry for every glyph in a font, with the good old bitmap font technique.
There are multiple formats around to work with, but I decided to stick with the one by AngelCode.
BMFont is a Windows tool that can export fonts installed in your machine as png textures, with a description file that can be exported as xml, text or binary formats.
Once an interpreter of this file format is written, it's then pretty easy to write dedicated classes to render text, both 2D or 3D.
I just open sourced a small Java library to load these file formats, together with a simple package to handle 3D rendering of dynamic text and a super simple sample app that should output something like:
Let's have a closer look at the project.
The main package, it.snada.bitmapfontloader contains classes to load and abstract bitmap fonts.
Loaders are classes with a single static method, load
that takes in a BitmapFont
object that will be loaded with font data, and an InputStream
pointing to the .fnt file exported from AngelCode BMFont.
font = new BitmapFont();
//Loads from a xml .fnt file
AngelCodeXmlLoader.load(font, getResources().openRawResource(R.raw.arial_xml));
//Loads from a text .fnt file
AngelCodeTxtLoader.load(font, getResources().openRawResource(R.raw.arial_txt));
//Loads from a binary .fnt file
AngelCodeBinLoader.load(font, getResources().openRawResource(R.raw.arial_bin));
This is basically it! You can navigate your font object and find all of the information loaded for you.
What if you want an example on rendering a text in 3D? Well, the other package. it.snada.bitmap3dstring does just that.
Keep in mind it's a very simple implementation, that may have limitations for many applications around or rendering code written by others: I believe it's just a starting point to understand how to approach this kind of problem that I use to quickly prototype ideas and apps.
My solution features an additional sets of classes that, using a single 1x1 quad (just 2 triangles), can render any string, dinamically, by generating the correct model matrix for each char in a string, and rendering it swapping the uv buffer to get the right texture coordinate.
First of all, let's get our geometry quad: since it's always the same for every glyph, Bitmap3DGeometry
is following the singleton pattern, and always returns a single object containing vertices, normals and indices informations:
Bitmap3DGeometry geometry = Bitmap3DGeometry.getInstance();
//This object contains geometry, normals and indices information to use in render
geometry.getNormalBuffer();
geometry.getVertexBuffer();
geometry.getIndexBuffer();
If your rendering code also needs vertices colors on top of the texture one, there's an helper class to create an handy object here too:
//This will create color information (RGBA, values within 0 and 1) equal for every vertex on the quad
//There's another constructor to specify information on every single vertex
Bitmap3DColor color = new Bitmap3DColor(1.0f, 0.5f, 0.3f, 1.0f);
Now, let's instantiate a 3D string:
Bitmap3DString string = new Bitmap3DString(bitmapFont, "Hello!");
It's important to note that this string can be updated on the fly with new text, and everything will be taken care for you:
string.setText("This can be dynamically calculated!");
Apply some transformations:
// Use this methods to set position, scale and rotation
string.setPositionX(1.0f);
//If you wish to set scale according to given width/height, helper methods are there too
string.setXScaleByPreferredWidth(1.0f);
//...and remember to update other dimensions as well...!
string.setScaleY(string.getScaleX());
And you are ready to render:
for (Bitmap3DChar chr : string.get3dChars()) {
//Every char contains a buffer with UV texture coordinates
chr.getUvBuffer();
//Every char contains a model matrix with every transformtaion, also the ones applied at string level
chr.getModelMatrix();
//Use this as vertex buffer
geometry.getVertexBuffer();
//Use this as index buffer
geometry.getIndexBuffer();
//Use this as color buffer
color.getColorBuffer()
}
There are sure better ways to handle transformations than this very simple api, but I needed something this simple to quickly develop the apps I have in mind.
And this, for me, does the job perfectly.
If you want to give this a try, it's published on both jCentral and Maven: simply edit your gradle file:
dependencies {
...
compile 'it.snada:bitmapfontloader:1.2.0'
}