Home | Blog

Some Recent Project Progress


As the Spring semester kicks off, things are going pretty well right about now. Course material is still pretty manageable, and my schedule permits me to have breakfast at a pretty decent time each day, surely this has a positive morale impact. And what comes with morale boosts is productivity perhaps.

I've made a number of changes pretty recently on the NitroPaint front, mostly with regard to texture compression quality. I toyed around with the idea of voronoi iteration in the palette generation algorithm, to try to find a locally optimal palette given the existing code produces a good starting point for search. This idea works pretty well when neglecting to consider the DS's limited color channel bit depth. This means that new clusters are susceptible to collisions, producing redundant duplicate colors, or producing clusters that get rounded out of usefulness in favor of other clusters. Due to this, for now, I'm limiting this extra stage to "small" palettes of no more than 32 colors. Later on if I can find a good way to address these deficiencies I may expand it into all palette sizes, but for now that may be a far-off dream.

Further changes have also been made to 4x4 compression in particular. Endpoint refinement was added to the interpolated palette generator right after doing principal component analysis. It only runs 2 search iterations allowing for a search range of +/-2 in the red, green and blue directions of both endpoints. More than this does seem to make a noticeable speed decrease for not much increase in quality, so this is something that would be great to optimize further. In addition, I raised the threshold of interpolation from 24 to 64 for average maximum squared YUV difference, which corresponds roughly to an 8-bit RGB difference of about +/-4 in the red/gree/blue channels, which is about as fine of detail the DS will be able to preserve anyway, making it a more sensible number I think. The result of these is that interpolation is more-used, and the interpolated palettes created are more optimal for their tiles.

Additionally, I did fix a couple of bugs in the compressor. One such bug was that if a texture contained at least one completely transparent 4x4 tile, then 2 palette colors would be dedicated to black colors. Interestingly, this is also a problem OPTPiX iMageStudio seems to exhibit. NitroPaint now simply ignores those tiles in processing to circumvent the issue. Another two bugs were in the interpolated palette generator code, and actually mostly cancelled each other out. One bug was in the color counting code, which was used to determine if a tile had 2 colors or less. Instead of correctly counting unique colors, it would simply count the number of opaque pixels. The result of this was that principal component analysis was run more than is necessary, which didn't produce any actual artifacts, but made compression slightly longer. The other bug was that, when creating a 2-color palette for a tile of only one unqiue color, an array was accessed out of the bounds it was initialized, which would produce a garbage color in the palette. Both of these combined to almost neutralize each other, except in the case where a 4x4 tile was transparent except for exactly one pixel, which would let garbage data leak into the palette. These have all been addressed.

Also as of late, I've resumed work on trying to decompile Mario Kart DS's network code. I started back in around December, but haven't worked much on it since then. Turns out, apparently, that Compiler Explorer is a very useful tool in doing this! No idea how I'd cope in the long run going without. Some stubborn functions still don't want to match yet, but surely those will be figured out with time. But for now, the actual size of binary I've actually managed is a measly 1.7KB.