Using rtl Print Compressed Fonts

From Uzebox Wiki
Jump to navigation Jump to search

Introduction

One of the most useful features of the RTL(Ram Tiles Library) is the ability to use ram tiles to draw text to the screen. Sometimes there is not enough tiles left to fit in 256-RAM_TILES_COUNT 8 bit vram limit but you have a title screen you want text on anyways, or you you just want to save massive space on a font set you would otherwise have to duplicate in several places. Either way you need a way to turn the normal 8 bit per pixel graphics you might get using Gconvert or Tile Studio into the 1 bit per pixel data RTL expects. This would be possible with a program, but it is also done easily manually. This tutorial will also cover how to setup and draw your text to the screen and special considerations involved. Basically you should find all the information you need(in conjunction with the RTL documentation) to get started using compressed fonts with no special requirements.


Special Considerations

The rtl_Print series of functions uses font data that it loads into ram tiles and then sets the vram indices to the correct letters to display the string commands you place. The library uses 1 ram tile per character that is used to store the actual pixel data, but after that you can draw that character anywhere in any number with no additional ram tile cost. To do this, we must make a character list which will specify every letter to load into ram tiles. This list is easily made manually simply by writing out what text you are going to display and then putting every unique letter or character into the string. The limitations here are obvious, you cannot have more unique alpha/numerals than you have ram tiles. Honestly this is rarely a problem and a screen of text probably uses 24 of the 26 letters, a period, a comma, a hyphen...this is all well under the 36 ram tiles that are easily had with most any game at this point. If you are drawing some sprites on the same screen you will have to load this data starting at a ram tile location that will not be used by those sprites(easily specified in the setup function).


Tile Conversion

First find a font tile set you like as per normal and convert it to tiles with your preferred method. Maybe you already have a full ascii set converted that's taking up 4k! If so lets make it takes 512 bytes instead with the exact same appearance. This method is not terribly difficult to do manually with a text editor, but making changes later gets tedious. I have made a small program *file needed* that will take data in either Gconvert or Tile Studio(and probably many other) formats and convert the HEX values into binary so that the resulting compressed font set is still human readable. Just check the compressed result versus your input file and you can probably make out the letters easier than originally. The program takes at least 1 parameter being the file to convert. If a second parameter is specified, it will be used as the name of the output file so you set this up to happen right after gconvert in your makefile.

Code Setup

As per usual with RTL, you must include rtl.h in your program. To use the text features you need to call a function to set it up. This function might look a little intimidating until you see the explanation of what it all is.

void rtl_RamifyFontEx(uint16_t rtoff, const int8_t *cmap, const int8_t *chrlst, const uint8_t *ftiles, uint8_t backcolor, uint8_t fontcolor)
  • uint16_t rtoff- This specifies where to start holding your font data. Sometimes in a title screen or similar situation, you will use a couple sprites for a cursor, decoration, etc. Since these sprites will be blit using ram tiles starting from 0, we need to make sure that it wont corrupt our font data. We should understand how ram tiles work in mode 3, and that 1 8x8 sprite can take 1,2, or 4 ram tiles to draw, and so after determining the max number of ram tiles that will be required by any position possible, we use the one after that as our starting point. If we have 4 sprites that could move anywhere, that could take 16 ram tiles and so 0...15, we would pass 16 as the argument and we'd be ok.
  • const int8_t *cmap- Here we specify which list of letters to use. If we were going to have a menu that had the words "RESUME OPTIONS QUIT GRAPHICS SOUND" we would build a map such as:
const int8_t title_font_map[] PROGMEM = "RESUMOPTINQGAHCD"

and pass it as the second parameter. The character map should have one of every letter that you will end up using, so if you inspect you will see that those 3 words only have 16 unique letters total and so using this method we can ensure we only need 16 free ram tiles to display it. The letters do not need to be in any particular order, but be careful not to duplicate any as that will end up wasting space.

  • const int8_t *chrlst- So we already have a list of what letters we want to load into ram, but we also need a way to specify which letters are actually in the compressed tileset. Someone might just need a set that has uppercase alpha characters, while someone else might need upper and lower case along with all the standard ascii symbols. This allows flexibility to fit different requirements. Something like:
const int8_t charlist[] PROGMEM = ":?>{}[],.^v!ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";

would specify that our fontset contains all those characters and nothing else. Here the order must exactly match the actual graphics data or everything will be off. Games not requiring a large font set can save a few bytes, and if you were crazy about saving space you could eliminate letters like q if you never need them in your game. Just make sure this matches the data!

  • const int8_t *ftiles- Simply pass the compressed font array you have created and it will be used. This is nice because the compressed font sets take up 1/8 the space of normal font data and so it is very feasible to have more than 1 font style in your game. You can recall the function at different parts of your game using different font set. There can only be 1 type of font on the screen at once, but you could reload a new font at any point and as long as the new font set has all the characters being used, all the characters on screen would still be there just drawn with the new look.
  • uint8_t backcolor- This is just the background color to draw with your font. The compressed font is converted from it's original 8bpp format into a 1bpp format. Each pixel in the font set specified with *ftiles is either 0 or 1 and where it is 0 this backcolor is drawn. You can make the same text match many different screen colors just by changing this value.
  • uint8_t fontcolor- This is the same thing as backcolor, except for the actual pixels that determine the shape of your letters. Any place in the font data there is a 1, this color will be drawn. Experiment with recalling the function each frame with a different color to do different text effects for almost no cost.


Examples

This is covered elsewhere in the RTL documentation but it could use some additional demonstration. Now that we know how to get all the required data setup, we just need to know how to use it. It's easy. Let's make a black screen, where the text changes color every frame.