Archive

Archive for the ‘Slideshow’ 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.

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:

Slideshow: Optimisation and Bugfixing

April 11th, 2007 Ant No comments

(Written 01/04/2007)

Back to it again. Today I’m altering the slideshow so that it allows the user to skip to the next image or to the end of the slideshow, by either tapping the touchscreen or pushing a button. Should be fairly simple, but the fading process makes it a little more complex.

When the fade calculations are occurring, the slideshow is in a subroutine that can take a few seconds to run. We need to remember if an event has occurred that could cause the slideshow to skip during this routine so that there isn’t a few seconds of “dead time” during which the user can’t interact with the DS. We can’t fade out immediately because of the need to do the precalculations, so we just remember the event and process it when we get back to the main loop.

Another update I’m working on is using the memcpy() command to output to the screen instead of drawing each pixel one by one. I’m surprised that the PALib doesn’t already use this - having done some tests, it seems that using memcpy() to output an image in one go is significantly faster than looping through the array of pixels.

(Some time later)

It seems that the “dead time” solution was no good. Although it worked perfectly, the fact that the system was essentially locked up whilst the fade frames were being calculated, nothing else could happen at the same time. This isn’t a problem on a normal system, but the DS has two screens - we can’t just have a slideshow on the top screen and nothing on the bottom one.

What I’ve done instead is calculate a single frame of the fade every time the main slideshow play() function gets called, until all frames have been calculated. This means that the DS doesn’t lock up for a significant amount of time. It would be possible to change the function so that only half of a fade frame is calculated each time the play() function is called, which would result in the function taking less than a frame to run, but the problem with this is that each image would therefore be on-screen for much longer whilst the extra steps are runnng.

(Some more time later)

Actually, scratch that. I’ve implemented the half-frame calculation system to enable me to have something going on on the bottom screen whilst the slideshow is running. I’ve also stripped out the “skip to end” functionality, because there’s no practical way to make it work with all of the caching I’m doing.

(Some more time later)

I’ve now modified it so that I can specify exactly how much of each fade frame to generate in each loop by changing just one variable. Whacking it down to 1/4 fade frames per VBL, reveals that the real speed problem now is probably more to do with drawing the bitmaps than generating the fade images, so I’m keeping it at 1/2 fade frames per VBL.

I’ve also discovered and, excitingly, fixed, a bug in the PALib. The “Pad.Held.Anykey” function wasn’t checking the status of the Y button. An awful lot of complicated digging into the internals of PALib revealed this bit of code:

type.Anykey = (!(!((pad&2047))));

This just checks if any single bit in the button bitmask is set, and returns 1 if so (0 otherwise). However, the Y button has a value of 2048, so its bit is masked out. Changing it to this fixed the problem:

type.Anykey = (!(!((pad&4095))));

I’ve submitted the bug to the PALib forum; let’s see what happens!

Categories: PALib, Slideshow Tags:

First Steps – Bitmap Crossfading and Memory

April 11th, 2007 Ant No comments

(Written 31/03/2007)

1:30 AM. Been hard at work on this for hours. My plan was to have a professional-looking logo sequence, and this basically means having high-quality images that cross-fade into each other. High-quality images generally means 16-bit. Making a fast, good-quality 16-bit cross-fade effect is, I’ve discovered, bloody difficult.

First of all, there’s the sheer amount of data involved. The DS has a resolution of 256x192, which gives us 49152 pixels. In 16-bit mode, each of these pixels is worth two bytes, which makes a total of 98304 bytes of memory, or roughly 96K. To make a cross-fader, we need two images, which is 192K. To do it quickly, we need to pre-calculate each step of the fade, so we multiply the size of a single image by the amount of steps in the fade, and add it to our running total. Assuming 15 steps produces a smooth transition, that’s (15 * 96) + 192, or about 1.5MB of data.

The DS has 32MB of RAM.

Anyway, a cross-fader in 16-bits works like this (different from the 8-bit version, which relies on producing a single intermediate image and performing palette adjustments on it):

  • Loop through every pixel in the first image;
  • Get the colour of the pixel;
  • Subtract that colour from the colour of the same pixel in the second image (remembering to break it into RGB components first);
  • Divide the result by the total number of steps in the fade;
  • Multiply that result by the number of the current step;
  • Add the pixel colour of the pixel from the first image.

As a formula:

px3 = px1 + (i * (px2 - px1) / t)

Where px3 is the faded pixel, i is the current fade step, px2 is one of the RGB components of the pixel from the second image, px1 is the same from the first image, and t is the total number of steps in the fade routine. This is apparently called “linear interpolation”; I looked it up when I was half-way through coding the routine to discover that I was, yet again, re-inventing the wheel.

Actually coding this was incredibly difficult, mainly because of bugs in the PALib, the compiler, the emulators, and my own inexperience with C++. Today I discovered:

  • Using PA_Print or PA_OutputText crashes DeSMuME;
  • Declaring an array with more than 32768 elements (ie. greater than the upper boundary of a signed int) crashes No$GBA.

I learnt how to create arrays dynamically using malloc(), free the memory again using free(), create pointers to arrays of structures, and even create pointers to arrays of structures containing pointers to arrays of structures and retrieve data from the whole mess afterwards. This was mainly to avoid the 32768 array limit - bitmaps have 49152 pixels! This only seems to happen with C++, though, for some reason.

I also learnt how to output directly to the NDS’ screens without using the PALib functions - there’s a handy pointer called “PA_DrawBg”, which is actually a multidimensional array that points directly at the video memory for the two screens. This line of code draws a black pixel at the top-left of the bottom screen:

PA_DrawBg[0][0] = 0;

This was amazingly useful.

Anyway, once I’d got this all written, I hit a snag. Initially, I pre-calculated the amount that I’d need to increase each pixel by (96K of RAM), and calculated the actual increases on the fly. There was such a lot of data flying around that it just wasn’t smooth enough. I could see the program redrawing the screen, so it was obvious that I needed to optimise it. The solution was to have everything pre-calculated, hence the huge memory requirements outlined above. Even that was too slow - although the fades themselves were now perfect, the images were now on screen for far too long whilst the fade calculations were performed. So, I allocated another 96K of RAM to storing the pre-calculated amounts that the pixels had to be increased by again. This boosted the speed of the algorithm by about 5 times, and gives me a perfect system.

Today’s handy class is called “Colour16Bit”. It enables me to get or set the RGB components of a colour value independently.

Categories: PALib, Slideshow Tags: