New Features Part Deux: Font System

posted in A Keyboard and the Truth for project 96 Mill
Published March 22, 2005
Advertisement
Now we move on to the second problem/feature:

first off, those of you who might be saying...

"WTH? they released a beta and they dont have text capabilities in-game already???"(as somone said to me last night).

Rest assured that MW does have text capabilities, and 'fairly' good ones, there are, however a few issues.

MW is built with the Flare 3.0 engine, and one of it's core features is API abstraction, that is, the engine has a 'virtual' Graphics and Sound API, and a DLL adaption system is used to change the concrete implementation of that API at run time.

So, with this system, MW can run using Direct3D, or DirectDraw, GDI, OpenGL, etc.

The virtual graphics API looks somthing like this:

GFXInitializeDevice
GFXLoadImage
GFXCreateImage
GFXQueryDevice
GFXQueryImage
GFXBlt
GFXStretchBlt
GFXFlip
GFXDrawText
and so on and so forth...

Now, when this system was designed, we were using only GDI or DirectDraw, it was later that we decided we wanted the Modulation and Alpha Blending goodness that came with 3D APIs, and while this came with a big headache already, there is still another headache to deal with.

Drawing Text in GDI and DirectDraw, is fairly easy, making use of the GDI commands to do so. In Direct3D it is somewhat harder, especially due to the inefficancy and inflexability of the ID3DXFont object.

To make matters worse, GDI does not support an easy way to 'stroke' text(giving the characters an outline, so they are readable on a 'busy' background), also characters can only be drawn using a solid color, needless to say, for games(where creativity and visual appeal flexability is paramount), this just won't do.

EUREAKA!

So the solution that many people use, is a 'bitmapped' font system, wherein an image, ususaly 256x256 or 512x512, is split into 16x16 cells, and the characters are drawn within it, these characters can later be blitted out when drawing text, this image can be brought into your favorite paint program, and stroked, or beveled or textured, or drop shadowed, etc etc, so font style flexability is maxamized.

Oh, we forgot one thing though... Now that we have this lovely 16x16 bitmap of characters, how to we make that into lines and paragraphs of text with decent formating... Well as they always say the Devil is in the Details.

So to save myself some pain up front, I make use of an availibe bitmap font maker LMNOpc Bitmap Font Maker, it works good, and has an important feature, Character Width Export.

A bitmap of characters alone will get you text, but unless you used a monospace font it is going to look awful. So by making use of character width data, we can get some fairly nice character spacing going on that makes our text look much better.

So, the basic idea, is to move the text facilities out of the adaptors and into the engine, making use of the engine side, Image Loading and Blitting capabilities (which end up being adaptor dependant), this is one less thing to implement in a new adaptor, and it will provide, very stylish and fairly consistant text across our adaptors.

So, we have our Font Bitmap and our Widths data, now what?

now comes the hard part:
after some experementation, and much laying awake in my bed, I came to a few conclusions.

Single Line, Top Left Aligned text:
if this is all you are after then life is easy, you can simply iterate over each character in your string, find the coresponding cell on the bitmap and blt it out using the apropriate character width. We need a little more than this so I had to press on.

Single Line, Top Left/Center/Right Aligned text:
If you want horizontal alignment then you need to do some extra work. You must perform two passes, the first will only measure the string, not draw it. Now that you know how wide the resulting string would be, you can change your starting X, apropriately, for left,center and right aligned text. Once you know that render the text as before with the proper X offset.
Again, we need more, as would any self respecting engine, I would hope =)

Multi Line, Top Left/Center/Right Aligned text:
Ah hah, here is where things get fun. Now, multi-line means two things to us: 1.a line-break in the string will force a newline. 2. a horizontal overflow within the FIRST out of bounds whitespace, results in previous whitespace line-break

this seems to be a little more complicated, but it really isnt that bad. As before our first pass is to measure the string, however, this time around we have some additional criteria.

We scan until we get a single line, And a single line is:

  • up until we hit the null terminator

  • up until we hit a line break

  • up until we hit white space that is out of our bounding rectangle


  • in all cases, this 'line scan' function, should let us know the line we are dealing with, via the return of a line length in characters, also as before we should record the line length in pixels.

    Now the last rule from above is the trickiest, but we can make short work of it, every time a white space character is encountered, we check if we are out of bounds(our line length in pixels thus far) and if we arnt, we record this spot as our last good white space, we also record our last good line length, which is including the space. If we come upon another rule (terminator or line break or white space) that happens to be out of bounds, then we refer to our last saved information, and return that is the end of our line. this line can then be rendered out, and the proccess will start over again making use of the bit of line that was out of bounds before.

    This is all the functionality we want, so we will be using this method.

    On a side note, for the present all that has been discussed is Top Vertical alignment, this is all we need really so I am not going to cover other methods in depth, but I can give a bit of a hint.

    Vertical Alignment
    to perform vertical alignment along with all of the other methods explained you need to 'conceptualy' render out the entire body of text, keeping track of how many lines are produced, once you know how many lines there will be *and knowing the height of each line* you can then offset them vertically properly for the kind of alignment you are looking for.

    Final Feature
    One nice feature is the ability to 'clip' text that falls out side of it's rectangle, coarse clipping is the simplest, coarse meaning the moment a character is partially out of it's area you dont draw it. this is as simple as checking the right and bottom (or left and top, depending on your alignment) extents of a character, against the coresponding bounding edge of the rectangle, this clipping feature is very handy for text used in UI componetns that require text to scroll, without being draw over certain parts of the UI. Fine clipping can also be performed by properly modyfying how much of a character you draw depending on how far out of the rect it is.

    So. While this is slightly challenging, it certainly isn't impossible =) and it's not that much work to get great looking infinitely styleable text =D

    Previous Entry MIA? AWOL? Hardly!
    0 likes 2 comments

    Comments

    Mushu
    Yep - I had to deal with all of that a couple weeks ago. Which was a bitch since SDL_ttf (the piece of crap I was using) created a new surface every time you wanted to actually render text.

    So, inevitably I ended up saving each glyph in a char-to-surface map, which made rendering a hell of a lot easier. Creating a "textbox" multi-line class wasn't hard at all. Mine's essencially a deque/queue of lines of chars. New line? Push it onto the back. Too full? Pop one off the front. Want some fun? Incriment random chars in random lines by random amounts.

    The problem came when I realized that SDL_ttf doesn't give you all the glyph metrics you'd need, namely the distance between the max height and the baseline (as opposed to absolute height) and some other stuff. So everything falls dead onto one line, all the chars that go below the line (g,j,p,q,y) "float" and stuff like ("'`^) fall down. It sucks.

    YAY FOR SHITTY LIBRARIES!!!
    March 22, 2005 01:59 PM
    jbadams
    A very interesting read, I'm going to be working on this myself shortly, and you've saved me some of the work conceptualising a design.
    April 06, 2005 04:08 AM
    You must log in to join the conversation.
    Don't have a GameDev.net account? Sign up!
    Profile
    Author
    Advertisement
    Advertisement