2009-11-08

Bitmaps Refactored

Woopsi supports two different kinds of bitmap data. The first is the usual PAGfx/grit-style data containing BMP files converted to C sourcecode. These are compiled into the final ROM file as const u16 arrays. I’m not sure that the DS has a hardware-enforced region of read-only data, so these arrays might be mutable, but it makes sense to treat them as const as they fall within the address space of the ROM file.

The second type of bitmap data is non-const. Until very recently, this kind of data could only be created by instantiating a Bitmap object and using the built-in drawing tools to doodle on it. However, it is now also possible to load data from the flash cart in the form of BMP files and store it inside a Bitmap object.

Both methods of accessing BMPs have their pros and cons. Embedded bitmaps take up memory even if they are not currently being used and pose a development problem - any changes to a BMP mean that the C code must be regenerated. Non-embedded bitmaps must be loaded from disk and therefore necessitate the inclusion of libfat (extra ROM size), imply more files on disk (install complexity), and are awful for testing (need to look into creating a FAT image at some point).

Regardless of the BMP access method used, the Bitmap object has become far more valuable. The Woopsi API currently uses pointers to raw bitmap data and width/height values for interacting with bitmaps, but it makes much more sense to simply pass around pointers to Bitmap objects. However, because of the two types of bitmap data that exist, this is not as simple as it seems.

The Bitmap object allocates a region of RAM based on the width and height supplied in its constructor. It has methods to change that memory and will delete it when the object is destroyed. This is great for blank bitmaps and loaded bitmaps (they are loaded a byte at a time and drawn to a blank bitmap to prevent memory waste that would occur if loading the entire file at once and trying to discard the unused portions). It isn’t at all good for embedded bitmaps. The memory cannot be deleted and does not need to be instantiated. It cannot be changed, so the drawing tools are useless.

To get around this, Woopsi now contains three Bitmap classes. The most basic is a new “BitmapBase” class. It contains just the absolute minimum functionality needed from a bitmap in Woopsi - width and height members/getters, a method for retrieving the raw u16 array, and a method for getting the pixel at a specific set of co-ordinates. The existing “Bitmap” class inherits from this, but is otherwise unchanged. The third class, “BitmapWrapper”, extends the base class with a constructor that accepts a pointer to a const u16 array as a parameter. It does not allow the data to be altered, nor does it attempt to delete it when the object is destroyed. By using this class, embedded bitmaps can be utilised throughout Woopsi in the place of newly created or dynamically loaded bitmaps.

I’m planning to go through the API and swap all functions that accept a u16 array/width/height combination of parameters to use a single Bitmap pointer instead. This gives rise to another problem - the Bitmap class as it stands is a very heavyweight object. It carries around all of the drawing tools with it.

After putting some thought into this, it seems appropriate to move all of the drawing tools into a separate class. A Bitmap object could produce a new object capable of drawing to it in the same way that a gadget can produce a GraphicsPort. The new class would be essentially the same as the “Graphics” class in Java. It may even be possible, once all of the refactoring is done, to combine the proposed new class with the existing GraphicsPort class (or at least work out a common base class).

Comments

Chase-san on 2009-11-10 at 21:55 said:

libfilesystem, you can keep the images themselves in the rom itself, and just load them when needed, which means no extra files need to be copied and also do not bulk up the size of the binary. As for libfat, it is not very large.