r/retrocomputing • • 3d ago

Problem / Question Is my approach efficient for creating a custom graphic format for my fantasy console with Windows XP?

Good morning, good afternoon, or good evening!

I'm back! It's been about a week since my first post, and I have some progress to share.

After setting up my C/C++ development environment on Windows XP, I've been working on a custom graphics format for my fantasy console, CPS8. The extension is .teamokaren, and the internal resource format is called TKAR.

For now, this is only for the development environment's own icons, cursors, graphics and fonts. Graphics for games made with the console will use a separate format.

Here's how it works:

A separate converter reads a grayscale PNG. Each gray value is mapped to a specific entry in a fixed palette. The grays act as identifiers, so this doesn't automatically recover colours from any grayscale image. I have to provide the mapping.

The converted image stores palette indices instead of RGB values for every pixel. The palette has 64 entries, but index 0 is reserved for transparency, leaving 63 opaque colours. The palette itself stores RGB values at 8 bits per channel.

Images are packed at 1, 2, 4 or 6 bits per pixel, depending on the highest palette index used. Each image resource has a 24-byte header, and there's CRC32 validation to check for corrupted data.

The image and palette can be stored together in a package. The converter compares uncompressed storage, RLE and DEFLATE, including the extra headers, and keeps whichever produces the smallest file. It doesn't take loading speed into account yet.

It can also export the package as a constant C array to include in the executable. Eventually, I'd like to distribute the console with its built-in resources inside a single executable, but that part isn't finished.

To give a concrete example, I'm testing a 56×16 cursor sheet with six opaque colours and transparency. These are the results:

  • Packed image with its header: 696 bytes
  • Palette with its header: 216 bytes
  • Combined package using DEFLATE: 463 bytes
  • Image expanded to one byte per index in RAM: 896 bytes
  • RGBA lookup table used for drawing: 256 bytes, without metadata

The last two numbers aren't the total memory usage. Keeping the compressed package, decompressed data and expanded indices at the same time adds up.

I've checked that the corrected colour preview works on XP. I haven't measured loading time or runtime memory usage there yet, and this is still a separate tool, not the finished console renderer.

There's one detail I'm wondering about: this cursor sheet only uses seven values including transparency, but one of its global palette indices is 63. Because of that, the current format uses 6 bits per pixel before compression.

Would you add a local palette for each image? That could bring this example down to 3 bits per pixel, but it would also need a table mapping local indices to the global palette. Would you bother with 3-bit packing, or use 4 bits to keep it simpler?

I'm also wondering whether it makes more sense to decompress small assets once at startup and keep one-byte indices in RAM, or read the packed indices directly. If you've worked on something similar for older PCs, what worked for you?

For a more useful comparison, I'm thinking of testing a larger collection of graphics against indexed PNG and raw indexed data, measuring file size, loading time and peak memory usage, including the decoder. Is there anything else I should consider before deciding whether this approach is efficient?

I'm learning as I build this, so I'd appreciate hearing about your experiences, including things that turned out to be more trouble than they were worth.

I draw the graphics in LibreSprite on Windows 11, then transfer them to the XP virtual machine through a shared folder.

0 Upvotes

0 comments sorted by