tommyettinger / anim8-gdx

Adds support for writing animated GIF, PNG8, and animated PNG (including full-color) from libGDX
Apache License 2.0
41 stars 4 forks source link

read apng #1

Closed ValeriaShyshkina closed 3 years ago

ValeriaShyshkina commented 3 years ago

Is any way to load apng as array/list of Texture/Pixmap?

tommyettinger commented 3 years ago

I've looked into this, but it's pretty complicated, unfortunately. There's both the core issue (libGDX uses some system libraries to load PNGs, and those don't seem to handle APNG as far as I can tell), and the unrelated performance issue, which may or may not apply (an array of Textures doesn't perform as well as one big TextureAtlas that includes all the frames from the APNG). Loading an animated PNG would be nice as a feature, but would most likely harm the performance of a game, especially if multiple things on the screen were APNGs. Unless you need to load user-supplied APNGs at runtime, I would strongly suggest splitting up an APNG into its frames as separate images, then packing those frames into an atlas.

Here's an example; I'm using this APNG image as the basis. You can use http://apngdis.sourceforge.net/ to split up an APNG; I used its Windows GUI (I just needed to specify the name with an underscore at the end, like "apng_"). I ignored the text files in the directory and moved the original APNG to a different folder after running apngdis, since it just puts all the frames in the same folder as the APNG. Then I just did a normal texture pack (I used the free https://github.com/crashinvaders/gdx-texture-packer-gui , the latest source version, but you can also use the texture packer built into libGDX as part of gdx-tools, and that can optionally be done with code). That gave me this atlas (libGDX 1.9.13 format) and image, which I also optimized with oxipng to reduce its size ( https://github.com/shssoichiro/oxipng ):

AnimatedPNGAtlas.zip

The atlas is a tiny bit larger than the APNG in filesize, which surprised me, but you could pack it as part of a full set of animations that could all be displayed on-screen at once and as one OpenGL "draw call," without needing "texture swaps" to switch from one frame to another as separate Textures. Too many texture swaps really harm performance, and they're one of the few ways seemingly-simple 2D games can get noticeably-low frame rates.

I understand there are reasons to want to support APNGs, especially when things like iOS Stickers use APNG, and this might allow using them in some way. I'm not sure what I can do because all of the file loading is deep inside platform-specific code that libGDX calls, like the LWJGL (2 and 3, which have different loading code), Android, iOS, or GWT backends. Loading as a Pixmap would be nice, since it would let the frames be edited and sent back to an APNG, but it would still require some figuring out and somehow accessing very complicated Pixmap internals. Essentially, I would have to write a PNG parser that can handle APNG (or find an external one that's pure-Java and call that; libGDX's PNG parser does not handle APNG), convert that to Pixmap, and then return it.

Sorry, but this seems like quite a lot of trouble to go through for something that would usually have a performance penalty. I hope the apngdis approach I linked can be helpful, though. It isn't as convenient, but being able to combine all of your animations into one atlas can be a big improvement over dozens of individual frame Textures.