Duke Nukem II Animation Format
The animation files consist of multiple blocks/chunks, each storing the chunk's size and type as first values.
Main Chunk: (header size: 128 bytes)
0 | UINT32LE | size (size of the main chunk, equals file size) 4 | UINT16LE | type (always $AF11 for main chunk) 6 | UINT16LE | anims (number of animation frames) 8 | UINT16LE | width (screen width, always 320) 10 | UINT16LE | height (screen height, always 200) 12 | UINT32LE | unknown1 (always 8) 16 | UINT32LE | repeat? (6 in all files, except for NUKEM2.F4 where it is 0) 20 | BYTE | nulls (padding to the start of the first sub-chunk)
There is no padding between the sub-chunks! Chunk 2 starts directly after chunk 1. The main chunk contains anims+1 sub-chunks!
Sub-Chunks: (header size: 16 bytes)
0 | UINT32LE | size (size of the chunk, including the size value itself) 4 | UINT16LE | type (always $F1FA for Sub-Chunks) 6 | UINT16LE | count (number of internal chunks in this chunk, either 1 or 2) 8 | BYTE | nulls (padding to the start of the internal chunk)
Only the first sub-chunk in a file contains 2 internal chunks, the rest will only contain 1 chunk.
0 | UINT32LE | size (size of the chunk, including the size value itself) 4 | UINT16LE | type (either $B, $C or $F)
Palette Chunk ($B)
Always first internal chunk in the first sub-chunk.
6 | UINT32LE | one (always 1)
The size of a palette chunk should always be 778 bytes. The remaining 768 bytes contain a 256-color palette.
Main Image Chunk ($F)
Always second internal chunk in the first sub-chunk.
The data of the main image consists of RLE-compressed color indices for each pixel.
Each row is compressed individually and the first byte in each row gives the number of RLE-flags for the row.
The RLE-flags ("n") are SIGNED bytes. A positive value ($00 <= n <= $7F) indicates that the following byte is to be written to the image n times. A negative value ($81 <= n <= $FF) indicates the the following -n bytes are to be written to the image.
Animation Chunk ($C)
6 | UINT16LE | yOff (first pixel row to be altered) 8 | UINT16LE | rows (number of rows in this frame)
The animation chunks contain only color indices for the pixels that changed from the last animation frame. Therefore the data is in a different format.
The rows are still compressed individually with the first byte giving the number of RLE flags in the row (can be 0 if the row is unchanged!). But the RLE flags now consist of TWO bytes. The first byte (UNSIGNED!) gives the number of pixels that haven't changed since the last frame. So just skip that amount of pixels (keep the previous color index for those pixels or make the pixels transparent).
The second byte is the actual RLE flag (still SIGNED byte), but this time, the effect of positive and negative values is swapped!
This file format was reverse engineered by K1n9_Duk3. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)