Thursday, June 24, 2010

WP7: Word Wrapping in XNA, Made Easy

In Silverlight, formatting text is about the easiest task of all. Boldface? Different colors? HTML markups? Word wrapping? Bah--all these are trivial.

In XNA, though, there are no primitives for any of these features. Instead there are exactly two tools at your disposal: SpriteFont.MeasureString() and SpriteBatch.DrawString(). Neither of these know anything about formatting at all--and they're certainly not going to accomplish any word-wrapping for you.
XNA isn't the only environment that lacks this basic text manipulation toolset. After running into this wall several times, I've eventually settled on an approach: a CompiledText class that turns a plain string into a formatted, word-wrapped, ready-to-draw array of individual text segments. Each segment lives on a single line and has the same formatting options--italicized, boldfaced, color blue, whatever.
One of the nice things about this approach is that you can do the hard work of constructing the CompiledText object infrequently--only when the text to be displayed changes--and in your calculation time rather than while you're doing the actual frame rendering. Once you've built the object, actually rendering the formatted text is accomplished by a very tight loop that just iteratively makes SpriteBatch.DrawString() calls--minimizing CPU cost while drawing a frame.

The CompiledText class I've uploaded needs a second file to run: AnimationUtils.cs, which exports a SqueezeText method. This thing figures out exactly how much text you can fit onto a line, by calling the primitive SpriteFont.MeasureString() and running a binary search across the string. (For better performance, you might want to refactor this thing to only test at word-break boundaries; it's currently doing the measuring first, then finding word-break boundaries afterwards.)

By the way, those who take a look in AnimationUtils.cs will discover an HslColor class that allows you to convert an XNA color to hue/saturation/luminosity values, then change them and convert back to RGB. Great for fades and color-shifts and such. Also in there is a C# version of probably the oldest method I've ever written: a method for moving sprites from one square of a chess board to another with a nice pretty motion that speeds up at the start and slows down at the end.

No comments:

Post a Comment