Archive

Archive for the ‘Text Scroller’ Category

Vectors and Memory Leaks

April 25th, 2007 Ant No comments

After I’d got libnds working in VC++ I went back to coding DefenderDS with PALib. First task was to fix a bug that caused the game to crash if there were no humans left for landers to pick up. That was pretty simple.

Whilst fixing that, though, I realised that my sprite destructor wasn’t getting called when a lander or human was removed from their respective vectors, or when the vector was emptied. The empty code looked like this:

while (landers.size() > 0) {
    landers.pop_back();
}

I used this code because I’d read that using the “.clear()” method didn’t dispose of the objects pointed to by the pointers in the vector. Did some googling to work out what was going on, and it turns out that I’ve made a classic beginner’s mistake. The “pop_back()” method just removes the pointer. Now that I think about it, this is horribly obvious. So, I’ve changed the code to do this instead:

for (u8 i = 0; i < landers.size(); i++) {
    delete landers[i];
}
 
landers.clear();

No more memory leaks. I’ve fixed this problem in DefenderDS, MenuDS, SlideshowDS and ScrollingTextDS, but haven’t got around to releasing new versions yet.

Sine Scroller

April 11th, 2007 Ant No comments

(Written 08/04/2007)

More refactoring. I’m now splitting most of the ScrollingText class into a ScrollingTextBase base class. That will reduce the amount of repeated code in the sine scroller to almost none.

This is the first time I’ve tried working with inheritance in C++ in about 3 or 4 years, during which time I’ve used several other more modern OO languages, so trying to switch back to the unfriendly syntax employed in C++ is difficult. Still, after an hour or so of fiddling and reading I’ve got it all working. Now on to the sine scroller.

(Some time later)

The sine scroller now works, and I’ve fixed a few bugs in the rest of the code. It uses the same FIFO system as the scroller to move the Y position of each letter around.

Uploaded it to Simian Zombie.

Sine Scroller Screenshot

(Later)

Ah, it seems I’ll need to recompile the PALib with a specific commandline argument to enable WiFi support. I’ll probably ignore it for the moment and come back to it when I’ve got everything else finished. Assuming I structure everything properly, which is the reason I’m tackling presentation before the game itself, it should be easy to add it in at the end.

Menus, then. Structuring them is easy - this is exactly what I do every day at work. So, I’ve got a MenuButton class, a Menu class that contains a vector of buttons and sub-menus (instant menu tree) and a MenuSet class. The last one isn’t strictly necessary, but I’m planning to wrap a lot of generic functionality into that class instead of duplicating it down the tree and wasting memory. The only difficulty here is working out how to receive events from the menu - does C++ have an event system? Will I need to write one myself? How about a message queue instead? Or just using delegates? How do delegates work? (One phonecall later - they’re apparently “pointers to functions” in C++, not “delegates”.) Lots of research needed here…

(Half an hour later)

Not as difficult as I thought, then! Heh. It works like this. Inside the button class, we declare a pointer to a function as a member, like so:

private: void (*action)();

There are three things to note here. The type of the member should match the return type of the function that we’re making a pointer to, so the function “void myFunction()” would work, whilst the function “int anotherFunction()” would not. The next thing to note is that we declare the pointer inside brackets; this isn’t strictly necessary, but it’s apparently a convention that indicates the variable is a function pointer. The last thing to notice is the pair of brackets after the declaration - this lets the compiler know that we’re creating a function pointer. If the function we’re making a pointer to has arguments, these should be specified in the brackets. If we wanted to make a pointer to this function, for example:

int myFunction(int myInt, int anotherInt);

We’d use the following pointer:

int (*myPointer)(int myInt, int anotherInt);

For the purposes of the menu system, we just need to use the first example - a function with a void return type and no arguments. Once we’ve assigned the pointer a memory address (as you would with any other pointer, ie. “action = myFunction” - note the lack of brackets after the function), we call it like this:

(*action)();

All I have to do to make a button execute a function (defined in the main.cpp file) is pass the function to the button object as an argument and then click the button. Fantastic!

(Later)

Another PALib bug that I’d spotted before but hadn’t noted down. There’s an odd problem with the DMA_Copy() function. All of the parameters have to be in brackets or it doesn’t work properly. For example, the top line gives different results to the second line:

DMA_Copy(100 + 120, 200 + 220, 12, DMA_16NOW); DMA_Copy((100 + 120), (200 + 220), 12, DMA_16NOW);

Aside from the new bug, which I’ve worked around, the menu system works! I can display buttons of any size at any position on the screen. Clicking and holding a button changes its image to “selected”; releasing it performs the button’s action; and dragging the stylus off the button resets it to “unselected”. Once whatever it was that ran drops us back into the menu system it redraws itself. Each menu can have its own background image.

Things to do:

  • Buttons need a “selected by keypad” image, to allow the pad to work;
  • Keypad needs wiring up;
  • Functions to allow changing between submenus;
  • Refresh() function to force a menu to redraw (useful if the menu changes a variable (“lives”, for example) and needs to update itself);
  • Need a “back” button;
  • Animated buttons? Possibly not this time around…
  • Attach sounds to click and release events;
  • Transitions? Again, possibly not this time around.

It looks like the slideshow will only run once - trying to run it again crashes the DS. Need to look into that.

Categories: Defender DS, MenuDS, PALib, Text Scroller Tags:

Tidying, Optimisation and PALib Bugs

April 11th, 2007 Ant No comments

(Written 07/04/2007)

More tidying. I’m splitting the ScrollingText class out into a Font class, TextWriter class, and ScrollingText class, so that I can more easily create new classes like a SineScroller class, etc.

As part of this refactoring process, I found another bug in the PALib. Well, I say bug, but it’s really more of a standards problem. The PALib guys have used the printf() conversion “%c” to mean “change colour” rather than “output a single char”. This confused me for a while because, instead of getting single characters splatted on the screen, I was getting random strings of text.

I came up with this new function as a backwardly-compatible fix:

void PA_OutputChar(u8 screen, u16 x, u16 y, char text) {
char output[2];
output[0] = text;
output[1] = '\0';
PA_OutputText(screen, x, y, output);
}

Another thought about using the WiFi system. One of the things I love about recent open-source programs, especially on the Mac, is that they tend to automatically tell you when a new version is available. It should be pretty easy to get the game to fetch an XML file from my web server that contains the latest version of the game; quick check against the internal value will let us know whether or not we’ve got the latest version. I could even make it do other things, like update the scrolling text on the menu screens, list news/other games, etc. I could have a whole section for that. Hmm, maybe I’ll write that after the menu system. It’d need some planning, though - what is it for? What does it do? What use is it? Who will use it?

Had a think about optimisation when working with C++ objects, too - I read something about the amount of work done in calling a function, and now that I’ve done some assembly programming (Z80, m68k, CIL and a lot of reading) it all makes sense. Bearing this in mind, I replaced calls to class properties with local variables in the main font writer loop. Seems to have improved the performance a bit - the flicker in No$GBA (caused by its DMA copier not running at the correct speed) has shifted from the middle of the screen to 3/4 of the way to the right, which means the font writer is now running 1/4 of a horizontal scan faster.

DS Hardware Discoveries

April 11th, 2007 Ant No comments

(Written 06/04/2007)

No more coding today. Just split the ScrollingText class into h/cpp files and a separate directory, and released both it and the Slideshow library on Simian Zombie under the GPL. I briefly considered the LGPL, but to be honest I don’t really care if people use the libraries or not; I just want to see what people do with them if they are used. The GPL lets me do that, whilst the LGPL doesn’t.

I did manage to get hold of some interesting reading material, though, and it seems that the DS does in fact do hardware sprites - I thought that it might just have been something cobbled together in software by the PALib guys. I’ve also found out that the four backgrounds on each screen exist in hardware too.

Another thing is that the top-most bit in the 16-bit colours is to do with either alpha channeling or alpha blending, but I suppose that only really comes in useful when the other 3 backgrounds are on the go. PA_DrawBg must, therefore, point explicitly at BG3 for each screen to prevent drawing being done through it on the other backgrounds. That means I’m not drawing directly to the display like I thought; I’m drawing directly to the last background, which is later combined with the other three backgrounds and sent through to some sort of display switching method, before finally being sent to the LCD itself.

The last thing I learned from trawling through the docs is that the DS has hardware to accelerate square root and division calculations. This doesn’t appear to be supported by the PALib yet.

Oh, and another last thing I learned (adding this later) is that the X and Y buttons work completely differently to the other buttons on the system. It looks like the majority of the buttons are just implemented using bog-standard GBA hardware, whilst the X and Y, which weren’t present on the GBA, have been bodged in later.

Categories: Defender DS, Text Scroller Tags:

Horizontal Text Scroller

April 11th, 2007 Ant Comments off

(Written 05/04/2007)

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:

_|__________|A

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:

_|_________A|_

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”)”:

_|_________A|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.

Categories: Text Scroller Tags:

More Tidying

April 11th, 2007 Ant No comments

03/04/2007

More tidying today. I wanted to move the slideshow code into a subdirectory within the main “source” folder. Seems easy enough - move the files, change the include in main.cpp to “slideshow/slideshow.h”, try to compile. Doesn’t work.

More tedious researching and tinkering.

Finally discover, not from Googling but by mucking about with the makefile, that all I need to do is add the subfolder to the “SOURCES:=” line. I’ve now got a tidy project.

Back to coding. I’ve made the slideshow detect whether or not it needs to re-initialise the display based on whether or not the next image to show matches the bit depth of the previous image. It also switches off the crossfader when dealing with 8-bit images, so 8-bit images can now be dropped into a 16-bit slideshow with no negative effects.

Started work on the menu system now that the slideshow is done. However, after working out which classes I needed I got sidetracked with the idea of a text scroller - it’d go at the bottom of the menu in a thin horizontal strip. Unfortunately the PALib text functions can only position text in a grid system, which means I’ve got no choice but to implement my own from scratch if I want smooth-scrolling text.

Categories: DS Coding, Slideshow, Text Scroller Tags: