future TODOs: - more efficient/less hacky to-file API - more aggressive checking of invalid API arguments - NEON SIMD - API for writing pre-palettized data? https://docs.microsoft.com/en-us/windows/desktop/ProcThread/creating-threads https://docs.microsoft.com/en-us/windows/desktop/sync/synchronization-barriers Regarding multithreading: I've considered adding multithreading support into the library, in the form of an asynchronous API. The reason for this is that, although the library is fast, it can still take several milliseconds to encode a frame on a slow machine, especially as the frames get larger. I figured it might be nice to have an easy way to call into the library without blocking on the main thread. However, this would also complicate the library significantly, as threading pre-C11 is very platform-dependent, and in my experience applications tend to want to do threading their own way, which the library should probably not impose on. The simplest multithreaded solution, which should be good enough for basically all uses of the library that I can imagine, is to simply run the single-threaded API in a background thread. This is easy enough to implement that I don't feel it's unreasonable to put the burden on library users to do this however they see fit. Multithreading is still not completely off the table, but I'm leaving it alone for now. FWRITE context: new/floor.gif, handle: 0x7fff9790c030, buffer: 0x110b40000, bytes: 17212, written: 1 FWRITE context: new/floor.gif, handle: 0x7fff9790c030, buffer: 0x7fc394010000, bytes: 14211, written: 1 FWRITE context: new/floor.gif, handle: 0x7fff9790c030, buffer: 0x110b40000, bytes: 17105, written: 1 FWRITE context: new/floor.gif, handle: 0x7fff9790c030, buffer: 0x7fc39580c200, bytes: 14034, written: 1 FWRITE context: new/floor.gif, handle: 0x7fff9790c030, buffer: 0x7fc394010000, bytes: 14197, written: 1 what's with it bouncing back and forth between high and low addresses like that? writing new/bouncy.gif width: 576 height: 360 frames: 417 centiSeconds: 3 ratio: 165.437682, branch1: 519526, branch2: 85949177 writing new/diwide-large.gif width: 768 height: 480 frames: 200 centiSeconds: 6 ratio: 9.454847, branch1: 7052021, branch2: 66675779 writing new/diwide.gif width: 384 height: 240 frames: 250 centiSeconds: 5 ratio: 8.506314, branch1: 2423626, branch2: 20616124 writing new/floor.gif width: 384 height: 240 frames: 247 centiSeconds: 2 ratio: 9.024288, branch1: 2270812, branch2: 20492461 writing new/increase.gif width: 576 height: 360 frames: 162 centiSeconds: 2 ratio: 8.881415, branch1: 3399529, branch2: 30192629 writing new/keyhole.gif width: 576 height: 360 frames: 299 centiSeconds: 3 ratio: 3.742903, branch1: 13072236, branch2: 48928105 writing new/odd.gif width: 381 height: 237 frames: 334 centiSeconds: 3 ratio: 148.888246, branch1: 201209, branch2: 29957655 writing new/tiles.gif width: 384 height: 240 frames: 625 centiSeconds: 2 ratio: 20.984519, branch1: 2619997, branch2: 54979378 writing new/anchor.gif width: 480 height: 320 frames: 171 centiSeconds: 4 ratio: 35.380525, branch1: 721964, branch2: 25543465 writing new/always-in-front.gif width: 480 height: 320 frames: 245 centiSeconds: 4 ratio: 47.166797, branch1: 781280, branch2: 36850475 writing new/flip.gif width: 480 height: 320 frames: 310 centiSeconds: 4 ratio: 25.791297, branch1: 1777282, branch2: 45838408