Back when I was programming mediocre games in AMOS, one of my friends decided he wanted to code too. I introduced him to the basics and he quickly advanced way beyond me. Whilst I was struggling to get simple things working in BASIC he was writing demo effects - fire, spinning 3D environments, toruses - in Pascal and C. One of the most impressive programs that he wrote, at least to me, was a BMP loader. I had no idea how to go about writing anything like that. I put it down to two things:
- BASIC, and the way it hides all implementation details from the coder to the point that he finds himself doing nothing but bolting together existing library functions (ie. “loadBMP()”, “saveBMP()”, “makeAnAmazingGame()”);
- The total lack of any useful books on coding where I grew up.
You could point out that if he could learn with no books, I could too, and he’s probably just smarter than me. That’s probably true.
Anyhoo, having just spent a month manually serialising objects for network transmission in C++ (exciting new project to be released soon), I decided it was time to write my own BMP loader for Woopsi.
Instead of leaping straight into the C++ code, I figured I’d make a prototype in Python first:
This is a Python 3 class that can load BMP files in either 1, 4, 8 or 24-bit colour depth. 16-bit support would be possible fairly simply, but I didn’t have a BMP in the right depth whilst writing this. It can only load uncompressed bitmaps. Finally, it supports all versions of the BMP DIB header, but it treats V4 and V5 as V3 and discards the extra data.
Once that was written, getting a C++ version created was simple. Woopsi now has two new classes in the “bonus” folder:
- BinaryFile, which can read and write binary files (works with both the SDL and DS libfat versions, as libfat is POSIX compliant for files);
- BitmapIO, which can load and save BMP files.
The Woopsi version is rather more limited than the Python version. It will only load and save 24-bit bitmaps. It can only deal with version 3 of the DIB header (the most popular BMP format, as far as I can tell). It will only load uncompressed bitmaps.
Usage is like so:
// Loading Bitmap* bitmap = BitmapIO::loadBMP("/mypicture.bmp"); // Saving BitmapIO::saveBMP("/myotherpicture.bmp");
Writing the BMP code highlighted a number of bugs in other parts of Woopsi, all of which are now fixed. The Bitmap::getPixel() method didn’t work for bitmaps larger than 65535 pixels. The Bitmap::drawBitmap() method wasn’t calling DC_FlushRange() before trying to DMA copy the source bitmap, leading to rows of black pixels. The SuperBitmap class has an overload for drawBitmap() that accepts a Bitmap object.
Lastly, there’s a new example program demonstrating the BitmapIO functionality.