After a short break in order to be suddenly horrendously ill, I’m working on this again. The text scroller is now finished. It’s got some neat (I think) ideas in it.
The scroller works like this. First of all, we need to know how much information we can show at once. The maximum length of a string that can be displayed at any time is 256/w, where w is the width of the current font (and 256 is the width of the DS’ screen). So, assuming we have an 8x8px font, that’s 32 characters. In this instance, the scroller creates a character array of 32 characters plus 2 more - it is important to have the extra two so that characters can gradually appear on one side of the screen and gradually disappear on the other. All of this gives us an arrangement like so:
Pipes represent the edges of the screen, whilst underscore represents a slot in our array. Just imagine that there are 32 underscores between the pipes, okay?
Next, we get the first character to display and put it into the right-most slot. If the first character is “A”, we have this arrangement:
After a VBL, we wipe the row and redraw it x pixels to the left (where x is the speed of the scroller). Once we’ve scrolled in this way by the width of a single character, we shuffle the entire character array along by one element, ending up with this arrangement:
We now return to the start of the loop - grab the next character from the string we’re currently scrolling through, insert it into the right-most slot, and reset the amount we’ve scrolled by. Next time we draw the screen we have this arrangement (assuming the next character is “B”)”:
Now we just repeat until we’ve scrolled through all of the characters in the string we’re trying to display. It’s essentially a FIFO buffer that we shake backwards and forwards like a sieve; each shake moves the FIFO along one place and a new character drops into the entry slot.
To make things easier outside of the class, we store a vector of character arrays to display inside the scroller. This lets us break up our text into smaller strings; it just makes working with the class easier. We could, for example, do this:
text.addText("First text string. "); text.addText("Second text string. ");
If you have a lot of text to add to the scroller, this would be very handy.
To deal with multiple strings in the vector, we just remember which string we’re currently displaying. If we get to the end of the string (detect using the standard ‘\0’ terminator), we move to the next string. Our FIFO buffer already contains the characters from the previous string that we’re still interested in. If we run out of strings, we go back to the first string.
Another tricky thing the scroller does is take a 16-bit bitmap and use it as the font. I basically pinched the technique from the PALib, but it’s really nothing more complex than a sprite sheet. Assuming we have a fixed-width font, the bitmap is 256px wide, we know the width of the font and the letters are arranged in ASCII order, we can extract each letter pretty easily. This alone gives me the ability to splat 16-bit fonts down on top of 16-bit images at any co-ordinate, which is one (two!) up on the PALib.
Finally, the scroller has the ability to either print the text with a specific background colour or with a transparent background. The size of the background is set in the class’ constructor. One function handles both scenarios. What the class does is create a 16-bit array and fill it with either a single colour or the data within the screen that falls within the background’s area. It draws this to the screen each loop immediately before the text is rendered. This is a trick I remember from my Blitz Basic days - we create a buffer before drawing to the screen and unbuffer the display to restore the original state at the start of every loop. Instead of redrawing the whole screen, we just redraw the parts corrupted during the loop. Things I might do to improve the class:
- Add a sine wave to the y axis (everyone loves a sine scroller);
- Allow left-to-right scrolling (currently only does right-to-left);
- Alpha blending on the text (probably too slow to be feasible).
Performance-wise, the DS seems to be able to run three scrollers (fonts 8x9 or 8x8) simultaneously without any problems. Trying three when one of those has an outsized font (16x18) results in flicker.
The most useful thing I learned today is the existence of the DMA_Copy() function. It must be some sort of hardware-accelerated memcpy() routine, similar in functionality to the Amiga’s blitter. It’s noticably faster than memcpy(), and it completely blows a pixel-by-pixel loop out of the water.
The other thing I’ve learned is that I’m still not really using PALib other than as a guide to the DS hardware. Looking through the code to the scroller, I’ve only used three PALib functions - DMA_Copy(), PA_WaitForVBL() and PA_DrawBg. One of those is actually a pointer to the graphics memory and the other two are so simple that they’re implemented as defines instead of proper functions. On the other hand, in the two weeks I’ve been programming the DS, I’ve written my own image display routines, a crossfader, new font routines, new text routines, 16-bit colour routines and a C++ bitmap wrapper class. I’ve also found at least three bugs in the library and fixed one of them.
Oh, one last thing that I should remember. There’s a couple of bugs in the slideshow. If there’s only one image it seems to go a bit crazy, and if the crossfader is switched off it goes a bit mental too.
(Some time later)
Whilst I think about it, I’ll write down my thoughts on music for the game. I’m going to have to go back to OctaMED to do this - I loathe all of the PC trackers but Renoise (which is easily the best tracker I’ve ever used), but Renoise doesn’t save MOD files. OctaMED is the only choice. Working with more than four channels enables me to hide my general tracker incompetence to some degree, so switching back is going to be difficult. The game will only have music on the intro/title/menu screens, and the style of the MOD will really affect the presentation of the game. Options so far:
- Wing Commander-esque orchestra (done it before, not too hard);
- Project-X-style dance track (very hard to do well, easy to do badly);
- Agony-style meandering piano (easy with more than four channels).
The first style would give the game an atmosphere of space opera pomposity. The second would make it seem like the worst kind of Bubble Bobble Evolution remake. The last one might be too laid back.