GAF File Format

Document version 1.0

This is a description of the GAF file format used by TA to store all kinds
of graphic elements, including animations, static pictures, user interface
elements, etc.

Credits:
This document builds on the original by Saruman and Bobban.

In addition, I got much helpful info from Bizmut, Kinboat, and Manu.

I even figured a couple of things out myself, but the people listed above
did most of it.

Warning: This is intended for use by people that already know what they're
doing.

I'm a C programmer, so I'm doing things in C notation here, but I'll try to
explain it so that those of you that don't speak C will be able to
understand.  If you don't understand, write me at joed@cws.org and I'll try
to clear things up.

I'm also a big believer in examples, so I'll be walking you through a GAF
file (Archipelago.GAF) as I explain.

The first part of the file is the header, which looks like this:

typedef struct _GAFHEADER {
  long IDVersion;  /* Version stamp - always 0x00010100 */
  long Entries;    /* Number of items contained in this file */
  long Unknown1;   /* Always 0 */
} GAFHEADER;

Let's look at a sample header:
00000000  00 01 01 00 39 00 00 00 00 00 00 00

IDVersion is 0x00010100 like we expect.  Entries is 0x39, indicating that
there are 57 items contained in this file.

Immediately following the header is a list of pointers, one for each entry.

The list of pointers here looks like:
00000000                                      68 EA 04 00
00000010  98 EA 04 00 C8 EA 04 00 F8 EA 04 00 78 EB 04 00
00000020  A0 EB 04 00 C0 ED 04 00 40 EE 04 00 68 EE 04 00
00000030  98 EE 04 00 C8 EE 04 00 F8 EE 04 00 78 EF 04 00
00000040  A8 EF 04 00 C8 F1 04 00 48 F2 04 00 78 F2 04 00
00000050  A8 F2 04 00 D8 F2 04 00 08 F3 04 00 88 F3 04 00
00000060  A8 F5 04 00 28 F6 04 00 58 F6 04 00 88 F6 04 00
00000070  B8 F6 04 00 E8 F6 04 00 18 F7 04 00 B8 F7 04 00
00000080  E8 F7 04 00 20 FB 04 00 C0 FB 04 00 F0 FB 04 00
00000090  20 FC 04 00 50 FC 04 00 80 FC 04 00 20 FD 04 00
000000A0  68 00 05 00 08 01 05 00 38 01 05 00 68 01 05 00
000000B0  98 01 05 00 C8 01 05 00 68 02 05 00 98 02 05 00
000000C0  F0 05 05 00 90 06 05 00 C0 06 05 00 F0 06 05 00
000000D0  68 07 05 00 28 08 05 00 58 08 05 00 88 08 05 00
000000E0  B8 08 05 00 E8 08 05 00 18 09 05 00 48 09 05 00

The next byte after the pointer list is at offset F0.  Remember this.

Each pointer points to a structure that looks like this:

typedef struct _GAFENTRY {
  short Frames;    /* Number of frames in this entry */
  short Unknown1;  /* Unknown - always 1 */
  long Unknown2;   /* Unknown - always 0 */
  char Name[32];   /* Name of the entry */
} GAFENTRY;

The first pointer is directs us to location 0x04EA68.  Going
there, we find:

0004EA60                          01 00 01 00 00 00 00 00   t...............
0004EA70  46 72 6F 6E 64 30 31 00 00 00 00 00 00 00 00 00   Frond01.........
0004EA80  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................

This entry has 1 frame, and is called 'Frond01'.

Following each entry is another list of structures, one for each frame.

typedef struct _GAFFRAMEENTRY {
  long PtrFrameTable;  /* Pointer to frame data */
  long Unknown1;       /* Unknown - varies */
} GAFFRAMEENTRY;

The frame entry looks like this:

0004EA90  78 D5 03 00 02 00 00 00

PtrFrameTable is 0x03D578.  This points us to a structure containing data
about the first frame in this entry.  It looks like this:

typedef struct _GAFFRAMEDATA {
  short Width;         /* Width of the frame */
  short Height;        /* Height of the frame */
  short XPos;          /* X offset */
  short YPos;          /* Y offset */
  char Unknown1;       /* Unknown - always 9 */
  char Compressed;     /* Compression flag */
  short FramePointers;  /* Count of subframes */
  long Unknown2;       /* Unknown - always 0 */
  long PtrFrameData;   /* Pointer to pixels or subframes */
  long Unknown3;       /* Unknown - value varies */
} GAFFRAMEDATA;

Here's the data:

0003D570                          31 00 1F 00 15 00 0F 00
0003D580  09 01 00 00 00 00 00 00 F0 00 00 00 00 00 00 00

Width and height are (duh) the width and height of the frame.  This frame is
0x31 by 0x1F pixels (49 x 31).

XPos and YPos are actually offsets that give the displacement of the frame
from the entry's actual position on the map.  So if the entry itself was
placed at position 100,100, the frame would be at position
100-XPos,100-YPos. These offset can be negative.  Here, they place the frame
at 21 pixels left, and 15 pixels above the initial placement of the item on
the map.

Unknown1 is always 9.  No idea what it really means.

Compressed is the compression flag.  If it's 0, the image is not compressed.
This image is compressed. More on this in a bit.

FramePointers.  This is where it gets a little weird.  If FramePointers is
0, then PtrFrameData points to pixel data.  If it isn't, then PtrFrameData
points to a list of that many more pointers to GAFFRAMEDATA structures. 
Each of these subframes is collectively treated as one frame.  More in this
in a bit.

Unknown2 is always 0.

PtrFrameData points to the pixel data or to more GAFFRAMEDATA structures,
depending on the value of FramePointers.  Here it's pointing to offset 0xF0.
If you remember, this is the first byte after the list of entry pointers way
back at the start of the file.

Unknown3 is a mystery.  Sometimes the value is 0.  Sometimes it isn't.  No
idea what it means or how to calculate it.

Ok.  Now we have this frame entry.  Since FramePointers is 0, PtrFrameData
points to pixel data.  If the frame were not compressed, it'd just be the
raw pixels, 31 chunks of 49 bytes each, corresponding to each line.  This
frame is compressed, so things are a little different.

Let's look at the data:

000000F0  07 00 29 00 44 17 00 45 21 0E 00 1B 00 44 17 04 
00000100  44 B3 07 00 45 09 00 44 1B 10 00 1B 00 A3 0D 00
00000110  44 07 00 A2 03 00 A2 0F 00 44 1D 16 00 13 00 45
00000120  07 00 44 03 00 45 13 00 44 03 00 45 09 00 45 03
00000130  00 A3 1D 1F 00 15 00 45 07 04 44 A3 07 00 45 03
00000140  00 44 03 00 44 03 00 A3 03 00 45 03 00 45 03 08
00000150  44 B3 A2 1F 1D 00 09 04 45 44 0B 04 44 45 07 08
00000160  44 A3 44 03 00 A2 03 04 A2 B3 05 00 45 05 08 44
00000170  A3 B3 23 25 00 0D 00 45 03 04 B3 44 05 00 45 07
00000180  08 A3 44 B3 03 04 44 5B 05 06 45 05 00 44 03 04
00000190  A2 45 09 04 44 45 07 00 44 0F 2B 00 0F 00 A2 03
000001A0  00 45 03 00 45 03 00 44 03 00 45 03 04 B4 35 03
000001B0  00 B3 05 08 45 B3 44 03 04 A2 46 03 08 B4 44 A2
000001C0  05 00 44 0D 00 44 0D 2B 00 09 00 45 05 34 45 44 
000001D0  A3 45 A2 44 B4 45 45 B3 36 45 45 35 03 0C A2 46
000001E0  A3 45 03 04 45 46 03 00 A2 03 04 B3 45 03 00 45
000001F0  0B 00 44 0F 28 00 0B 04 45 A2 05 38 B2 A3 B4 A2
00000200  A2 B4 45 A2 45 45 A3 46 44 46 44 03 14 A2 46 46
00000210  44 B3 37 03 00 35 03 04 A2 45 05 06 45 13 2B 00 
00000220  04 A3 44 03 00 44 07 34 B4 A2 44 45 46 45 46 A2
00000230  A2 46 A2 B4 46 A2 03 04 B3 44 03 24 B2 A2 44 A2
00000240  36 A2 45 B4 A2 46 03 04 46 44 17 2A 00 09 08 44
00000250  A3 44 05 08 A3 45 36 03 60 A2 45 B2 45 45 A2 A2
00000260  B4 44 A3 35 45 A3 44 B4 A2 46 B2 45 A2 A2 B2 46
00000270  44 A3 07 04 A2 45 0D 29 00 0B 10 44 45 45 B3 45
00000280  03 60 46 44 45 46 A2 45 B3 45 B2 35 A3 44 B3 A3
00000290  B4 A1 46 45 45 A2 46 A2 B4 45 45 03 0C 46 44 A2
000002A0  45 11 2F 00 00 44 03 0C 44 A3 45 B3 03 04 45 35
000002B0  03 00 44 03 0C 45 B4 45 B4 03 58 46 A2 45 B3 44
000002C0  A3 44 45 A2 46 44 45 45 46 44 44 45 A2 44 45 B4
000002D0  A2 46 13 28 00 00 A3 05 00 45 07 00 46 03 00 45
000002E0  03 04 45 A3 0E 45 48 A2 46 45 A2 46 B4 A2 45 46
000002F0  B3 46 45 46 46 45 A2 A2 B4 A3 0A 45 15 31 00 0B
00000300  20 A2 45 45 35 B3 44 46 45 45 03 06 45 00 46 03
00000310  5C A2 46 44 A2 45 B3 45 45 46 36 B3 A1 A3 44 B2
00000320  A2 45 B4 A2 A2 B3 45 44 45 03 04 A3 44 05 00 44
00000330  2F 00 07 00 45 03 04 45 A3 03 14 B3 36 A3 B2 45
00000340  45 03 70 45 A3 B3 36 45 46 B3 A2 44 A3 45 A3 44
00000350  46 35 B4 45 B3 35 46 A2 36 45 B4 36 A2 A3 B2 45
00000360  0B 2C 00 09 00 45 07 0C A3 45 45 36 03 06 45 20
00000370  B4 45 A2 5B 46 36 45 B4 45 03 24 46 44 46 B3 A2
00000380  45 45 A3 A1 B4 05 0C 46 A2 B4 5A 07 00 45 09 2A
00000390  00 07 00 45 03 04 44 45 03 3C 45 B3 A2 45 45 38
000003A0  A2 45 44 45 45 46 45 45 A2 45 03 28 37 B4 45 A2
000003B0  46 44 46 45 46 45 45 07 00 45 13 26 00 09 28 A3
000003C0  45 B3 A2 46 45 A2 B2 A3 44 38 03 04 B3 45 03 00
000003D0  45 03 00 45 09 18 45 46 A1 36 B4 A2 46 05 08 B3
000003E0  45 45 17 27 00 0F 00 46 0A 45 08 A3 45 46 03 06
000003F0  5B 00 A3 03 0C 5B 45 45 37 05 04 45 A2 03 04 45
00000400  B4 03 04 45 A2 07 00 45 05 00 45 13 24 00 09 06
00000410  45 14 46 44 A3 44 B3 45 03 00 38 05 00 5A 05 04
00000420  44 A3 07 14 46 45 B2 35 45 A2 05 04 44 45 0D 06
00000430  45 0F 23 00 07 00 45 09 04 B3 37 03 00 45 05 00
00000440  36 03 00 44 03 04 45 B3 05 20 45 44 A2 46 44 A3
00000450  B3 44 45 0B 00 44 19 1B 00 0D 0C 45 A2 5A 37 0B
00000460  04 44 A3 03 04 46 A3 03 08 35 B3 45 07 04 B3 45
00000470  0F 00 A3 19 1C 00 0B 04 44 A2 07 00 46 07 08 44
00000480  46 44 07 06 45 03 00 45 03 00 45 03 00 35 03 00
00000490  A2 27 15 00 09 00 45 11 08 44 45 A3 09 00 44 05
000004A0  00 A2 0B 00 46 0F 00 44 17 0B 00 1B 00 A3 11 04
000004B0  B3 44 0D 00 44 25 08 00 19 04 B3 44 0B 00 44 3B
000004C0  07 00 19 00 36 0D 00 45 3B 07 00 27 00 A2 05 00
000004D0  A2 35 04 00 2B 00 44 37 

PtrFrameData points to a short integer that is a count of bytes for the
first line. Skip ahead that many bytes, and you get to a count for the
second line, etc, etc.  The first line is 7 bytes long, and consists of 29
00 44 17 00 45 21. The Height parameter tells you how many lines there are,
in this case, 31. Broken into lines, minus the length data, we get:

Line   0 29 00 44 17 00 45 21
Line   1 1B 00 44 17 04 44 B3 07 00 45 09 00 44 1B
Line   2 1B 00 A3 0D 00 44 07 00 A2 03 00 A2 0F 00 44 1D
Line   3 13 00 45 07 00 44 03 00 45 13 00 44 03 00 45 09 00 45 03 00 A3 1D
Line   4 15 00 45 07 04 44 A3 07 00 45 03 00 44 03 00 44 03 00 A3 03 00 45 03 00 45 03 08 44 B3 A2 1F
Line   5 09 04 45 44 0B 04 44 45 07 08 44 A3 44 03 00 A2 03 04 A2 B3 05 00 45 05 08 44 A3 B3 23
Line   6 0D 00 45 03 04 B3 44 05 00 45 07 08 A3 44 B3 03 04 44 5B 05 06 45 05 00 44 03 04 A2 45 09 04 44 45 07 00 44 0F
Line   7 0F 00 A2 03 00 45 03 00 45 03 00 44 03 00 45 03 04 B4 35 03 00 B3 05 08 45 B3 44 03 04 A2 46 03 08 B4 44 A2 05 00 44 0D 00 44 0D
Line   8 09 00 45 05 34 45 44 A3 45 A2 44 B4 45 45 B3 36 45 45 35 03 0C A2 46 A3 45 03 04 45 46 03 00 A2 03 04 B3 45 03 00 45 0B 00 44 0F
Line   9 0B 04 45 A2 05 38 B2 A3 B4 A2 A2 B4 45 A2 45 45 A3 46 44 46 44 03 14 A2 46 46 44 B3 37 03 00 35 03 04 A2 45 05 06 45 13
Line  10 04 A3 44 03 00 44 07 34 B4 A2 44 45 46 45 46 A2 A2 46 A2 B4 46 A2 03 04 B3 44 03 24 B2 A2 44 A2 36 A2 45 B4 A2 46 03 04 46 44 17
Line  11 09 08 44 A3 44 05 08 A3 45 36 03 60 A2 45 B2 45 45 A2 A2 B4 44 A3 35 45 A3 44 B4 A2 46 B2 45 A2 A2 B2 46 44 A3 07 04 A2 45 0D
Line  12 0B 10 44 45 45 B3 45 03 60 46 44 45 46 A2 45 B3 45 B2 35 A3 44 B3 A3 B4 A1 46 45 45 A2 46 A2 B4 45 45 03 0C 46 44 A2 45 11
Line  13 00 44 03 0C 44 A3 45 B3 03 04 45 35 03 00 44 03 0C 45 B4 45 B4 03 58 46 A2 45 B3 44 A3 44 45 A2 46 44 45 45 46 44 44 45 A2 44 45 B4 A2 46 13
Line  14 00 A3 05 00 45 07 00 46 03 00 45 03 04 45 A3 0E 45 48 A2 46 45 A2 46 B4 A2 45 46 B3 46 45 46 46 45 A2 A2 B4 A3 0A 45 15
Line  15 0B 20 A2 45 45 35 B3 44 46 45 45 03 06 45 00 46 03 5C A2 46 44 A2 45 B3 45 45 46 36 B3 A1 A3 44 B2 A2 45 B4 A2 A2 B3 45 44 45 03 04 A3 44 05 00 44
Line  16 07 00 45 03 04 45 A3 03 14 B3 36 A3 B2 45 45 03 70 45 A3 B3 36 45 46 B3 A2 44 A3 45 A3 44 46 35 B4 45 B3 35 46 A2 36 45 B4 36 A2 A3 B2 45 0B
Line  17 09 00 45 07 0C A3 45 45 36 03 06 45 20 B4 45 A2 5B 46 36 45 B4 45 03 24 46 44 46 B3 A2 45 45 A3 A1 B4 05 0C 46 A2 B4 5A 07 00 45 09
Line  18 07 00 45 03 04 44 45 03 3C 45 B3 A2 45 45 38 A2 45 44 45 45 46 45 45 A2 45 03 28 37 B4 45 A2 46 44 46 45 46 45 45 07 00 45 13
Line  19 09 28 A3 45 B3 A2 46 45 A2 B2 A3 44 38 03 04 B3 45 03 00 45 03 00 45 09 18 45 46 A1 36 B4 A2 46 05 08 B3 45 45 17
Line  20 0F 00 46 0A 45 08 A3 45 46 03 06 5B 00 A3 03 0C 5B 45 45 37 05 04 45 A2 03 04 45 B4 03 04 45 A2 07 00 45 05 00 45 13
Line  21 09 06 45 14 46 44 A3 44 B3 45 03 00 38 05 00 5A 05 04 44 A3 07 14 46 45 B2 35 45 A2 05 04 44 45 0D 06 45 0F
Line  22 07 00 45 09 04 B3 37 03 00 45 05 00 36 03 00 44 03 04 45 B3 05 20 45 44 A2 46 44 A3 B3 44 45 0B 00 44 19
Line  23 0D 0C 45 A2 5A 37 0B 04 44 A3 03 04 46 A3 03 08 35 B3 45 07 04 B3 45 0F 00 A3 19
Line  24 0B 04 44 A2 07 00 46 07 08 44 46 44 07 06 45 03 00 45 03 00 45 03 00 35 03 00 A2 27
Line  25 09 00 45 11 08 44 45 A3 09 00 44 05 00 A2 0B 00 46 0F 00 44 17
Line  26 1B 00 A3 11 04 B3 44 0D 00 44 25
Line  27 19 04 B3 44 0B 00 44 3B
Line  28 19 00 36 0D 00 45 3B
Line  29 27 00 A2 05 00 A2 35
Line  30 2B 00 44 37

To decode the line, to the following:

1. Read a byte.  This is a mask.
2. If (mask & 0x01) = 0x01
     skip ahead (mask >> 1) pixels.  This is transparency, allowing whatever
        was under the frame to show through.
   else if (mask & 0x02) = 0x02
     copy the next byte (mask >> 2)+1 times to output.
   else 
     copy the next (mask & 0x02)+1 bytes to output.
3. go back to 1, until there are no more bytes left in the line.

A C code fragment to do this is:

  char *data;  // points to pixel data

for (y = 0; y < FrameData.Height; y++) {
  bytes = *((short *) data);
  data += sizeof(short);
  count = 0;
  x = 0;
  while (count < bytes) {
    mask = (unsigned char) data[count++];
    if ((mask & 0x01) == 0x01) {
      // transparent
      x += (mask >> 1);
    else if ((mask & 0x02) == 0x02) {
      // repeat next byte
      repeat = (mask >> 2) + 1;
      while (repeat--)
        putpixel(x++, y, data[count]);
      count++;
    }
    else {
      repeat = (mask >> 2) + 1;
      while (repeat--)
        putpixel(x++, y, data[count++]);
    }
  }
  data += bytes;  // point to next line
}

We do this to the above mess of data, and we get:

Line   0                                                             44                                  45                                                *
Line   1                                        44                                  44 B3          45             44                                       *
Line   2                                        A3                   44          A2    A2                      44                                          *
Line   3                            45          44    45                            44    45             45    A3                                          *
Line   4                               45          44 A3          45    44    44    A3    45    45    44 B3 A2                                             *
Line   5             45 44                44 45          44 A3 44    A2    A2 B3       45       44 A3 B3                                                   *
Line   6                   45    B3 44       45          A3 44 B3    44 5B       45 45       44    A2 45             44 45          44                     *
Line   7                      A2    45    45    44    45    B4 35    B3       45 B3 44    A2 46    B4 44 A2       44                   44                  *
Line   8             45       45 44 A3 45 A2 44 B4 45 45 B3 36 45 45 35    A2 46 A3 45    45 46    A2    B3 45    45                44                     *
Line   9                45 A2       B2 A3 B4 A2 A2 B4 45 A2 45 45 A3 46 44 46 44    A2 46 46 44 B3 37    35    A2 45       45 45                           *
Line  10 A3 44    44          B4 A2 44 45 46 45 46 A2 A2 46 A2 B4 46 A2    B3 44    B2 A2 44 A2 36 A2 45 B4 A2 46    46 44                                 *
Line  11             44 A3 44       A3 45 36    A2 45 B2 45 45 A2 A2 B4 44 A3 35 45 A3 44 B4 A2 46 B2 45 A2 A2 B2 46 44 A3          A2 45                  *
Line  12                44 45 45 B3 45    46 44 45 46 A2 45 B3 45 B2 35 A3 44 B3 A3 B4 A1 46 45 45 A2 46 A2 B4 45 45    46 44 A2 45                        *
Line  13 44    44 A3 45 B3    45 35    44    45 B4 45 B4    46 A2 45 B3 44 A3 44 45 A2 46 44 45 45 46 44 44 45 A2 44 45 B4 A2 46                           *
Line  14 A3       45          46    45    45 A3 45 45 45 45 A2 46 45 A2 46 B4 A2 45 46 B3 46 45 46 46 45 A2 A2 B4 A3 45 45 45                              *
Line  15                A2 45 45 35 B3 44 46 45 45    45 45 46    A2 46 44 A2 45 B3 45 45 46 36 B3 A1 A3 44 B2 A2 45 B4 A2 A2 B3 45 44 45    A3 44       44*
Line  16          45    45 A3    B3 36 A3 B2 45 45    45 A3 B3 36 45 46 B3 A2 44 A3 45 A3 44 46 35 B4 45 B3 35 46 A2 36 45 B4 36 A2 A3 B2 45               *
Line  17             45          A3 45 45 36    45 45 B4 45 A2 5B 46 36 45 B4 45    46 44 46 B3 A2 45 45 A3 A1 B4       46 A2 B4 5A          45            *
Line  18          45    44 45    45 B3 A2 45 45 38 A2 45 44 45 45 46 45 45 A2 45    37 B4 45 A2 46 44 46 45 46 45 45          45                           *
Line  19             A3 45 B3 A2 46 45 A2 B2 A3 44 38    B3 45    45    45             45 46 A1 36 B4 A2 46       B3 45 45                                 *
Line  20                      46 45 45 45 A3 45 46    5B 5B A3    5B 45 45 37       45 A2    45 B4    45 A2          45       45                           *
Line  21             45 45 46 44 A3 44 B3 45    38       5A       44 A3          46 45 B2 35 45 A2       44 45                   45 45                     *
Line  22          45             B3 37    45       36    44    45 B3       45 44 A2 46 44 A3 B3 44 45                44                                    *
Line  23                   45 A2 5A 37                44 A3    46 A3    35 B3 45          B3 45                      A3                                    *
Line  24                44 A2          46          44 46 44          45 45    45    45    35    A2                                                         *
Line  25             45                         44 45 A3             44       A2                46                      44                                 *
Line  26                                        A3                         B3 44                   44                                                      *
Line  27                                     B3 44                44                                                                                       *
Line  28                                     36                   45                                                                                       *
Line  29                                                          A2       A2                                                                              *
Line  30                                                                44                                                                                 *

This is essentially a big green splat, used to represent a patch of
reclaimable foliage.

This entry is very simple.  One frame.  No subframes.  If there were
multiple frames, you'd display each frame in sequence.  If the FramePointers
member were not 0, then instead of pixels, PtrFrameData would point to a
list of pointers that had that many entries.  Each pointer would point to
another GAFFRAMEDATA entry.  When you are assembling that frame, you would
paint all the subframes in order, and treat the whole thing as one single
frame for animation purposes.

I think I've covered everything.  If you have any questions, let me know.

Joe D
joed@cws.org
