Yesterday evening, I set to the task of programmatically making some textured text in XNA. I was a bit puzzled as to why I couldn't find any tutorials about this. It's such a simple and nice-looking effect. Why had nobody done it before? So, about eight hours working time ago, I started.
I now know why it hasn't been done before.
Drawing textured text in XNA is very simple in itself, requiring less than a screenful of code, but it's far from obvious how to get started. For a start, it requires use of DualTextureEffect, which I only accidentally learned existed while I was looking for another possible solution involving depth buffers - they start with 'd' as well, so intellisense merrily alerted me to the existence of DualTextureEffect and I was put on a more promising path. But even then, despite giving you an effect for using two textures at once, XNA doesn't give you a vector format capable of using two textures at once, so you need a custom vector format to use with it first. I've been unable to find much help with this supplied online anywhere. Allow DPH Software to correct this oversight.
So, while this technique could theoretically be used for a few things, what I was interested in was making textured text during the code. Why would we want to do this, rather than just drawing our pretty text in a paint program? There are a few reasons I can immediately think of:
- The amount of text may mean that rendering it all would use too much memory - especially if you want it in different languages.
- You may want the texture on the text to itself be animated (or the text to be animated while the texture remains fixed relative to the screen).
Neither of these things apply to the demo I supply here, but I'm sure you can imagine the possibilities. So, how do we do it? As Shawn Hargreaves explains, The DualTextureEffect combines two textures with a rule that, while it's actually commutative (it doesn't matter which way round the textures are), is easier to imagine as one being the basic texture and the other being a multiplier. In this case, our basic texture will be some clouds, and the multiplier texture will be our text. To do whatever text we want in the code, we make that multiplier texture a rendertarget. The alpha channels of the two textures will be multiplied, so we clear this texture to 'Transparent', then draw text on it. Now when the alpha channels are multiplied, the result will be fully transparent for any part of the multiplier that was transparent - that is, any part we didn't draw the text on. The parts with text won't be transparent, so those parts will show the clouds texture - giving the result of textured text. The texture of the text will be in the original colour if the text was drawn in grey, twice as bright if it was drawn in white, and black (untextured) if it was drawn in black. RGB channels are multiplied separately, so drawing the text in some other colour would result in the texture being appropriately tinged.
Have a play with the WP7 demo supplied here, and feel free to reuse the code. Be aware, of course, that the dual texture vertex declaration supplied with this code has other uses besides text - instead of drawing text on your rendertarget, you could for example draw a simple lightmap with some spotlights moving round in realtime. In any case, I hope you can avoid the frustration I've encountered trying to implement this effect!