In previous font tutorials, we have seen how to use some
predefined fonts. Here, we will use our own custom font stored in a texture.
The idea of this tutorial is to render font using a texture which contains a
list of characters. A string will be rendered by rendering character by
character. Each character is rendered by drawing a textured quad, using the
texture region associated of the character.
The advantage of this technique is that you can design your own fonts and used
them in a 3D scene. The font picture can be generated either manualy or with a
generator using system font.
This next tutorial about OpenGl components will
use our font printer to render component's text.
Suppose that you have a picture in which you have a collection of characters :
Font picture
Each characters is positionned at a particular location and a
know dimension. Later, we will see how to determine the character region.
The picture can be divided in a bi-dimensiobal array, made of rows and lines,
like shown in the next picture :
Picture subdivisions
Know the associated character location (row, line), we can
easily associate its region.
We will see here how to determinate the character positions row
and line.
The simple way is to use the ASCII code.
The ascii code table associate an integer in the range [0, 256] to a character.
We will use the associated ASCII code
of the character to determinate its location.
The ASCII code contains 256 characters. The 32 first
characters are not used here (characters not representable). We will use only
the 224 last characters. Those 224=16*14 characters can be represented by a
bi-dimensional grid 16 x 14.
The corresponding font picture will contains 16 rows and 14 lines of
characters. The character at (0,0) have the ASCII code 32,
and on ...
In the next picture,
I've represented the character grid. Each grid elements contains the
associated characters ASCII code.
Character position
We can map easily a character c
to a (row, line) position in the grid with :
row = (c - 32) % 16
line = (c - 32) / 16
The interface for rendering text on the screen is simple. It is composed of an enumeration, used for the font alignement, and two overloaded methods which have the aim to render a String on the screen.
FontRenderer interface |
|
The picture used here is a 256x256 picture (in pixels). This picture contains 256 characters shared in 16 rows and 14 lines.
The character in the first rectangle have the code 32.
The region of a character can be represented by the coordinates of his top-left point. Effectivly, we know its size
as we know the texture size and the number of character per rows and lines.
So, the characters region size is (16, 256/14) =
(charWidth, charHeight).
First, we convert the ASCII code of a character to the location
(row, line) like seen previously. Then we calculate the upper left point of
the character region :
ASCII code to location of top-left point |
//Convert the ascii code into the position in the 16*14 array |
Now, we can render the character as a quad with the following code :
Render a character |
//Render
the character with a texture quad |
Note: Don't forgot the lower left corner of
the texture is (0, 0).
We have seen the basis to render a character, know we will render the full
String.
To quickly explain the code, it is composed of 3 parts :
- We enable and set-up the OpenGL states to render the text
(texture, blending ...).
- Then, we calculate the alignement offset.
- Before all the initialization steps, we loop over characters and render
them.
- To finish, the OpenGL states are restored.
Draw a complete String |
/** |
Note: If the texture font have an alpha layer (fontHaveAlphaLayer),
the appropriate blending function is used. Look at the
next paragraph to have more informations on how alpha layer is created.
The font picture used is a 2 bit picture
(black & white only). Character is composed of white
pixels, black pixels should be considered as transparent pixels.
To remove these pixels, we can use blending. For this, we affect an alpha of 0 for black pixels and an alpha of 1 for white pixels.
This can be done using the method createsAlphaLayer of the class
PictureEffects. This method returns a Picture
in which an alpha layer is added. Alpha is zero where pixels are full black,
else alpha is set to one. The alpha layer can be used to mask black pixels.
To have more informations on PictureEffects, look at the Tutorial 21.
The default font renderer is created like this :
Adding an alpha layer |
/** |
We have created an alpha layer on the texture, but how to use it ?
It is very simple, we enable blending to have access to the alpha value, and
we use the appropriate blending function :
Blending |
if(fontHaveAlphaLayer) |
If the alpha layer of the texture is not used, I mix equally source (font texture)
and destination colors (framebuffer color). Else, source and destination colors
are mixed accordingly to the alpha value.
In Tutorial 16, we have seen display lists for optimizing
rendering performances. We will use it here to render a font.
I've told you in the Advanced part of
the tutorial 16 a way to call multiple display lists with one call. Here is a concrete application of this.
First, we generate our display lists. A display list render a character
(...) and position to the next character
(glTranslate).
Display list version |
//Generate 256 adjacent display lists, one display list per character |
Now our display lists are created, we will see how to call them for rendering
a string.
For this, we will see the power of glListBase &
glCallLists to achieve such effect in one call.
Here are the description of the two methods used :
glListBase(listOffset)
glCallLists(numList,
format,
lists)
lists is an array of display list, the size of
the array is at least numList. Le glCallLists
method will render the list of display list.
For our application, we have a list of character which correspond to the index
of the display list. The first display list (index 0) is FONT (see the code
above). To use directly the byte[] representation of the string
(from getBytes()), we can use
glListBase with FONT as parameter. The result of
this is display list rendered will be offseted by
listOffset.
Suppose we want to render the string "a". The following code will be equivalent
to glCallList(FONT+'a').
Render a String |
//Render a string |
is equivalent to :
Render a String |
//Render a string |
F : switch between Font2D/Font2DL
Remember to download the GraphicEngine-1.1.2 to run this tutorial !
Tutorial 20 src (11 ko) //Port to Jogl JSR-231 initially done by Magarrett Dias
If you've got any remarks on this tutorial, please let
me know to improve
it.
Thanks for your feedback.
Copyright © 2004-2012 Jérôme Jouvie - All rights reserved. | http://jerome.jouvie.free.fr/ |