TLDR;
cleanRotation is a set of functions to generate and export image table containing all rotations for an image. It creates rotations with cleaner edges than the SDK rotation but there is also an option to have cleaner dithering instead.
CleanRotation v1.zip (174.1 KB)
@samdze also made a command line to generate this type of spritesheet
https://devforum.play.date/t/spriterot-handy-command-line-tool-to-generate-rotations-spritesheets/
Long version
Clean Outlines
If you tried to rotate images using the SDK function, you might have noticed that often the result get a bit fuzzy or even missing pixels.
After posting about cleanEdge, I decided to look a bit into this topic and the technic, often called RotSprite, is actually not that complicated so I made my own rotation function.
The idea is simply to upscale the image and afterward to rotate and downscale it. That's it.
cleanEdge is using a custom upscale algorithm but I used the much simpler scale2X which work quite well and is often enough for the type of resolution used on playdate.
Overall it improves a lot the outline of an image, removing the fuzziness we can see with the normal image rotation.
But one aspect it does not help is the dithering. If your image have a lots of dithering you will still have a lot of flickering and moiré pattern as you rotate your picture.
Clean Dithering
While I was finishing up with generating clean rotation, I saw this cohost post about an old trick to rotate an image using only shearing functions.
The results do not create cleaner image but the technic has one interesting property, since you just shift pixels with shearing (if you don't simply use an image transform) you just move pixels around. The result will have the same number of white and black pixels basically which would be great news to keep the dithering as close as possible to the original image.
And it works even better than I was expecting:
The dithering does not have the same pattern but the pattern give the same shade level and there is no flickering as the image is rotated. The drawback is that the outline can get even fuzzier than the SDK rotation.
Generating Image Table
Since these rotations are more expensive to use than the image rotation in the SDK, you cannot use them on the playdate itself (until someone rewrite everything in C). The way to use it in a game is to save them in an image table and at runtime use the image corresponding to the angle you want.
I've added the functions to generate the image table and also to export them as an image.
if playdate.isSimulator then
image = playdate.graphics.image.new( "my_image" )
rotation_table = cleanRotation.generate_imagetable( image, 90, "dithering" )
cleanRotation.export_imagetable( rotation_table, "my_image_table" )
else
rotation_table = playdate.graphics.imagetable.new( "my_image_table" )
end
You can choose to optimise the rotation for outline or dithering, it's depends mainly on the type of images you use.
By default the number of angle generated is 90, but that also depend of your image and how it is used in your game. If you have a big image, you might need a greater number of frame to look fluid.
There is also a handy function to get the correct image for an angle
angle = playdate.getCrankPosition()
cleanRotation.get_image_from_angle( rotation_table, angle ):drawCentered( 200, 120 )
If you want to rotate stuff, that might be handy!