PS2 Linux Programming

 

Rendering Text

 

 

Introduction

 

This tutorial will describe a method for rendering text to the screen. A bitmap font class contained in font.cpp and font.h will be used.

 

 

Bitmap Font Class

 

The bitmap font class loads a bitmap image into GSmem then display a chain of 2D sprites, each one being a font character. Most of the techniques used in this tutorial have been described in previous tutorials so only the font rendering process will be described here.

 

The bitmap file, font.bmp, that is included with the sample code is filled with a grid of letters. There are 16 letters per row and 16 rows. Each character in the bitmap is 16x16 pixels in size. The ASCII character 0 starts at the top left, and moving to the right increasing the ASCII character number. Moving to a new line increases the ASCII characters number by 16. The ASCII character number can be thought of as being the “frame” or character number that is to be rendered.

 

Starting with an ASCII character number, the row and column that the letter is on can be determined with the following code:

 

int tx = cLetter % LETTERSPERROW;

int ty = cLetter / LETTERSPERROW;

 

If tx and ty are multiplied by 16, the result is the UV coordinates of the top left corner of the required letter, which can then be used for rendering.

 

So why is the texture red? - When loading a font bitmap where RGB(0,0,0) is transparent, often and very annoyingly, there is an “almost black” colours that appears round the edges of the characters of the font. So while the bitmap looks great in Photoshop smoothed against a black background layer, it looks horrible against a light background on the PS2, since there is still the blackish outline around the edges which is not transparent. This would be unacceptable for a font class since the colour of the background onto which the text is to be rendered in not generally constant (or even known). The best way to solve this problem would be to have an alpha channel included in the texture so that the edges were smoothed by having low alpha around the edges. Then the outsides would be blended with whatever colour the sprite was rendered onto. Unfortunately BMP files don’t support an alpha channel, so instead of completely scrapping the BMP loading code for a more complex graphics format a workaround is to load the red channel of the bitmap as the alpha channel.

 

Some extra code has been added to ctexture.cpp so that when the bitmap is loaded, the parameter (flag) bRedAsAlpha determines whether the red channel is to be loaded as the alpha channel. If this flag is true, the loading process makes the texture pure white, but with a varying alpha channel. This means that the colour of the font can be changed by changing the vertex colour, since white multiplied by the vertex colour equals the vertex colour.

 

The font.bmp file supplied with the code is actually Times New Roman, which is not a fixed width font. In order to render the letters to the correct width, the character widths are loaded from the file font.dat. This file simply contains 256 8-bit numbers containing the width of the characters in pixels.

 

Creating a fonts is quite easy. All that is needed is “Bitmap Font Builder” from http://www.lmnopc.com/bitmapfontbuilder/ and follow these steps:

 

·        Load up Bitmap Font Builder

·        Go to the “Character Set” menu and select Full ASCII (0 – 255)

·        Choose the required settings for Font 1

·        Set the texture size to 256 x 256

·        Texture colours should be: background = black, foreground = red

·        Make sure “grid” is unchecked

·        Go to the “Font Smoothing” menu and make sure it is enabled

·        Next go to File -> Save BMP (this will save as a 24 bit bmp, but it may be better (in terms of size) to convert it to 8 bit).

·        Finally File -> Save Font Widths (Byte Format)

 

 

Texture Alignment

 

The following information is important when making a 2D game where the textures have to line up correctly. The PS2 offsets all its pixels by 0.5. Therefore pixel (0, 0) it is actually at (-0.5, -0.5). If something is rendered at pixel (0, 0), the bilinear filtering will blend that pixel between its 4 neighbours, distorting the texture. Remember that in 12:4 fixed-point 8 equals 0.5, so always subtract 8 from any XYZ2 values of the vertices to place the pixels of a sprite in exactly the same position as the pixels on the texture.

 

Observing the rendering function in the font class it will be seen that this technique is employed.

 

 

Using the Font Class

 

The font class is initialise at the start of the program by calling:

 

bool Initialise(const char * strFontBMP, const char * strFontWidths, void * pMemory, void * pCachedDMAMemory, uint32 GSStartTile, bool bDoubleHeightForTV = false);

 

The first two parameters are the two files exported from Bitmap Font Builder. The next parameter is the memory for the texture. The parameter after that is enough memory for the class to be able to build it’s primitives into. It is recommend that at least 64K of memory is allocated for this, but the actual amount needed will depend on the amount of text to be rendered. GSStartTile is the GS page where the texture is to be placed in GSmem when it is uploaded. The final parameter makes the text double height. This is good for use on a TV as the regular size font flickers quite badly in PAL / NTSC.

 

Once the font is initialised, the Begin() function is called before rendering. This function uploads the texture to GS memory.

 

There are four different rendering functions. The first function is:

 

void Render(const int x, const int y, const char * strText, uint8 R = 0x80, uint8 G = 0x80, uint8 B = 0x80, uint8 A = 0x80);

 

The parameters should be fairly self explanatory. The x and y parameters are the coordinates of the top-left of the string. The strText parameter is the text to be printed. The final 4 parameters are the colour and alpha value for the string.

 

RenderCenter() is the same function, but instead the x and y coordinates are those of the centre of the string.

 

Lastly there is printf() and printfc(), the first is the top left and the second is the centre version of these functions. These functions act exactly like printf so that values of variables etc. can be rendered to the screen without having to go through the trouble of manually putting variables into a string.

 

 

Conclusion

 

In this tutorial the use of a font class has been presented to allow text to be rendered to the screen.

 

 

Dr Henry S Fortuna

University of Abertay Dundee

h.s.fortuna@abertay.ac.uk