The FLIC file format

Skip to main content (skip navigation menu)






The FLIC file format

 

In this paper, you will find the file format specifications for a class of animation files that fall in the "FLIC" file category. These include:

FLI files (Autodesk Animator) FLC files (Autodesk Animator Pro)
FLH & FLT files (DTA) CEL files (Autodesk Animator)
FLX files (Tempra Pro, Mathematica Inc.) FLX files (U-Lead, 3DStudio MAX)
Extensions by Pro Motion (Cosmigo) Extensions by EGI (CompuPhase)

The original FLIC file format was described by its author (Jim Kent) in Dr. Dobb's Journal, March 1993. The original purpose of this document was to document the modifications and extensions that EGI (a FLIC compiler and player engine) adds to the FLIC file format, but since then it has grown to include all other extensions and variations as well. As you may not have Jim Kent's article, all standard file information is included in this paper as well.

There are two "official" types of FLIC files: FLI and FLC (the names of these types refer to the filename extensions). The FLI files are the older format and are limited to a resolution of 320×200. The FLC file format adds configurable resolution and better compression.

FLX files are a slight variation on the standard FLC format. Actually, there are two FLX file formats with slight differences. Both formats use 32768 colours in a packed RGB format (15-bpp, each pixel takes two bytes). The first FLX format was defined for "Tempra Pro" by Mathematica Inc. The format used by 3DStudio MAX (Discreet Inc.) also has the extension FLX but their format is more like that of 15-bpp FLH files. Where distinction is needed, this paper refers to "Tempra FLX" or to "Autodesk FLX" formats (Discreet is affiliated to Autodesk).

Both "Tempra FLX" and "Autodesk FLX" formats use the RLE compression that was originally designed for 8-bpp FLC files, which is a sub-optimal solution. To improve the compression and to make the file format more flexible with regard to colour depth, Dave K. Mason defined new chunk types for his DTA program, in addition to tagging the new format with a new "type" ID and new extensions (FLH and FLT) as to avoid confusion. A few other programs, notably EGI, also support the DTA chunks and type IDs.

CEL files, finally, are actually either FLI or FLC files with a different extension and one more chunk in the "prefix data" (a kind of optional header).

Overview

A FLIC file stores a number of frames. Every frame contains an image and possibly a palette, a label, or other data. Usually, a FLIC file contains a ring frame at the end, so that the animation can be played repeatedly without a perceptible pause between the last frame and the first (the unpacking of the first frame, a complete image, is generally slower than a delta frame update). A FLIC file that contains segments (EGI extension) optionally contains a ring frame per segment.

FLIC files are structured in a hierarchy of chunks. A chunk contains a fixed part and a variable part. The fixed part of every chunk contains the type and the size of the chunk. The rest of the chunk has no fixed format; it all depends on the chunk type. The purpose of the chunked structure is to allow new chunks to be added without breaking existing FLIC players. A reader that does not understand some chunk type can just skip it (using the information from the fixed part of the chunk). The figure below shows the hierarchy of chunks in a FLIC file.

All "word" (two bytes) or "double word" (four bytes) values are stored in Little Endian (this is the byte order used by the Intel 80x86 and Pentium processor series).

Overview of the FLIC file structure
File header                   general file information

Prefix chunk                  FLC files only
   Cel data chunk             CEL files (identical to FLC files)
   Frame chunk                overlay frame, EGI files only
       <image data>           overlay pixel data
       Cel data chunk         overlay origin and transparent colour
       <label data>           overlay label
   Path map                   EGI files only

Segment table chunk           EGI files only
   Segment chunk              information of every segment, EGI files only
   <label data>               symbolic names of segments, EGI files only

Huffman table chunk           EGI files only

Script chunk                  EGI files only

Frame chunk                   standard frame
   Postage stamp              icon, FLC files only
      <image data>            compressed or uncompressed
   Cel data chunk             frame origin, EGI files only
   <palette data>             colour data
   <image data>               compressed in various ways
   <mask data>                transparency information, EGI files only
   <label data>               symbolic or numeric labels, EGI files only
   Region chunk               region of frame changes, EGI files only
   Wave audio chunk           digitized audio, EGI files only
   User string chunk          general purpose data, EGI files only
   Key palette                key frame data, EGI files only
   Key image                  key frame data, EGI files only

Ring frame chunk              frame that cycles back
   <palette data>             see above
   <image data>               see above
   <mask data>                see above
   <label data>               see above
   Region chunk               see above
   Wave audio chunk           see above
   User string chunk          see above

<palette data> is one of either:
   "256" colour palette       palette with 8-bpp RGB entries
   "64" colour palette        palette with 6-bpp RGB entries

<image data> is one of either:
   Black frame                full black frame
   Uncompressed full frame    uncompressed pixel block
   Full frame                 RLE compressed, EGI also supports Huffman/BWT
   Delta frame (old style)    RLE compressed
   Delta frame (new style)    RLE compressed, EGI also supports Huffman/BWT
   HiColor/True Color frame   DTA and EGI only

<mask data> is one of either:
   Bitmap mask chunk          EGI files only
   Multilevel mask chunk      EGI files only
   Region mask chunk          EGI files only

<label data> is one of either:
   Label chunk                EGI files only
   Extended label chunk       EGI files only

The file header

A FLIC file starts with a 128-byte header, see the figure below for a C structure. The type field contains:

0xAF11For FLI files
0xAF12For standard FLC files (with an 8-bit colour depth). FLX files (both "Tempra FLX" and "Autodesk FLX") also use this header type.
0xAF44For FLIC files with a colour depth other than 8. The DTA program (by Dave K. Mason) makes FLIC files with a colour depth of 1, 15, 16 or 24 bits per pixel. EGI version 3.0 (and later) supports 16-bpp FLIC files.
0xAF30For FLIC files that use Huffman or BWT compression. These FLIC files can also have a colour resolution that is different from 8 bits per pixel.
0xAF31For FLIC files that use "frame shift" compression. These FLIC files may use additional compression schemes like Huffman and BWT; They can also have a colour resolution that is different from 8 bits per pixel.
???Password protected FLIC files have a scrambled type field, so that previous versions of EGI and other FLIC readers will identify them as invalid (or unknown) FLIC files.

For FLI files, the delay between two frames is in increments of 1/70 second; FLC files specify the speed in milliseconds. The header for a FLI file does not contain the offset of the first and second frames; the first frame is assumed to start directly behind the file header (no "prefix", "segment table" or "Huffman table" chunks) and the offset to the second frame is easily computed once you read in the header of the first frame. The purpose of storing the offset to the second frame is that, after playing the ring frame, the next frame to display is the second frame of the animation.

Autodesk Animator Pro also stores the MS-DOS formatted date and time stamps of the initial creation and last update of the FLIC file, as well as the serial number of the copy of the Animator Pro program that made/updated the file (in the creator and updater fields). Other utilities set the creator field to:

0Unknown (Pro Motion, DTA, VFD or other)
0x45474900EGI
0x464c4942FlicLib
0x42494c46FlicLib - release 2
0x41544542Micrografx Simply3D
0x30314c46Discreet 3DStudio MAX

The frames field in the FLIC file header does not include the ring frame that loops back to the beginning of the animation.

The flags field is used internally by Autodesk Animator Pro. If a FLIC file is written to disk and closed correctly, Animator Pro sets this field to 3. Several other utilities set it to zero.

The FLIC file header
typedef struct {
  DWORD size;          /* Size of FLIC including this header */
  WORD  type;          /* File type 0xAF11, 0xAF12, 0xAF30, 0xAF44, ... */
  WORD  frames;        /* Number of frames in first segment */
  WORD  width;         /* FLIC width in pixels */
  WORD  height;        /* FLIC height in pixels */
  WORD  depth;         /* Bits per pixel (usually 8) */
  WORD  flags;         /* Set to zero or to three */
  DWORD speed;         /* Delay between frames */
  WORD  reserved1;     /* Set to zero */
  DWORD created;       /* Date of FLIC creation (FLC only) */
  DWORD creator;       /* Serial number or compiler id (FLC only) */
  DWORD updated;       /* Date of FLIC update (FLC only) */
  DWORD updater;       /* Serial number (FLC only), see creator */
  WORD  aspect_dx;     /* Width of square rectangle (FLC only) */
  WORD  aspect_dy;     /* Height of square rectangle (FLC only) */
  WORD  ext_flags;     /* EGI: flags for specific EGI extensions */
  WORD  keyframes;     /* EGI: key-image frequency */
  WORD  totalframes;   /* EGI: total number of frames (segments) */
  DWORD req_memory;    /* EGI: maximum chunk size (uncompressed) */
  WORD  max_regions;   /* EGI: max. number of regions in a CHK_REGION chunk */
  WORD  transp_num;    /* EGI: number of transparent levels */
  BYTE  reserved2[24]; /* Set to zero */
  DWORD oframe1;       /* Offset to frame 1 (FLC only) */
  DWORD oframe2;       /* Offset to frame 2 (FLC only) */
  BYTE  reserved3[40]; /* Set to zero */
} FLIC_HEADER;

The modifications that EGI made to the FLIC file header are subtler. Not only are there a few added fields, but you must also decide whether the fields are valid:

Chunks and subchunks

Every chunk starts with a 6-byte header, that contains the size (four bytes) and the type (two bytes) for the chunk. All chunks sizes should be rounded up to an even number of bytes. The values of the main level chunks are above 0xF100, values of the subchunks are below 100 (decimal). As you can see in figure "Overview of the FLIC file structure", nearly all of the subchunks appear in the "frame" chunk.

Chunks types are indicated in the FLIC file with a two-byte value, but Jim Kent's article tagged names on those values (these names appear to be extracted from the Animator Pro source code). For ease of writing, I use the same names, in the same glorious ALL UPPER CAPS" that has become common in discussing the FLIC file format.

Overview of all chunks
   3       CEL_DATA             registration and transparency
   4       COLOR_256            256-level colour palette
   7       DELTA_FLC (FLI_SS2)  delta image, word oriented RLE
  11       COLOR_64             64-level colour palette
  12       DELTA_FLI (FLI_LC)   delta image, byte oriented RLE
  13       BLACK                full black frame (rare)
  15       BYTE_RUN (FLI_BRUN)  full image, byte oriented RLE
  16       FLI_COPY             uncompressed image (rare)
  18       PSTAMP               postage stamp (icon of the first frame)
  25       DTA_BRUN             full image, pixel oriented RLE
  26       DTA_COPY             uncompressed image
  27       DTA_LC               delta image, pixel oriented RLE
  31       LABEL                frame label
  32       BMP_MASK             bitmap mask
  33       MLEV_MASK            multilevel mask
  34       SEGMENT              segment information
  35       KEY_IMAGE            key image, similar to BYTE_RUN / DTA_BRUN
  36       KEY_PAL              key palette, similar to COLOR_256
  37       REGION               region of frame differences
  38       WAVE                 digitized audio
  39       USERSTRING           general purpose user data
  40       RGN_MASK             region mask
  41       LABELEX              extended frame label (includes symbolic name)
  42       SHIFT                scanline delta shifts (compression)
  43       PATHMAP              path map (segment transitions)

  0xF100   PREFIX_TYPE          prefix chunk
  0xF1E0   SCRIPT_CHUNK         embedded "Small" script
  0xF1FA   FRAME_TYPE           frame chunk
  0xF1FB   SEGMENT_TABLE        segment table chunk
  0xF1FC   HUFFMAN_TABLE        Huffman compression table chunk

The rest of the document discusses these chunks and subchunks in detail. On the right of the caption for each chunk type is the product for which this chunk is valid. Autodesk Animator is not mentioned explicitly, because there exist (to my knowledge) no chunks that only Animator supports.

all
PREFIX_TYPE
The prefix chunk contains (undocumented) settings and cel data. It usually appears in .CEL files.
typedef struct {
  DWORD size;           /* Size of the chunk, including subchunks */
  WORD  type;           /* Chunk type: 0xF100 */
  WORD  chunks;         /* Number of subchunks */
  BYTE  reserved[8];    /* Reserved, set to 0 */
} PREFIX_HDR;
all, EGI 3+, EGI 4
CEL_DATA
typedef struct {
  DWORD size;           /* Size of the chunk, always 64 */
  WORD  type;           /* Chunk type: 3 */
  short center_x;       /* Coordinates of the cel centre or origin */
  short center_y;
  WORD  stretch_x;      /* Stretch amounts */
  WORD  stretch_y;
  WORD  rot_x;          /* Rotation in x-axis (always 0) */
  WORD  rot_y;          /* Rotation in y-axis (always 0) */
  WORD  rot_z;          /* z-axis rotation, 0-5760=0-360 degrees */
  WORD  cur_frame;      /* Current frame in cel file */
  BYTE  reserved1[2];   /* Reserved, set to 0 */
  WORD  transparent;    /* Transparent colour index */
  WORD  overlay[16];    /* Frame overlay numbers */
  BYTE  reserved2[6]    /* Reserved, set to 0 */
} CEL_DATA;

The CEL_DATA chunk is usually not present in FLC files. Intermediate files used by Autodesk Animator Pro with the .CEL extension usually contain a CEL_DATA in the prefix chunk. The CEL files have the same format as FLC files.

EGI version 3.0 and later may generate CEL_DATA chunks inside normal frames; i.e. outside the prefix chunk. EGI uses the CEL_DATA chunk to hold the origin of the frame. Sprite animation toolkits can use the origin of a frame for run-time "registration" of the frame. (Registration is a term that animators use to mean the correct positioning of a frame in relation to the other frames and to the background image.)

EGI uses only the center_x and center_y fields of the structure. The center_x field gives the horizontal offset of the origin relative to the left edge of the frame. The center_y field is the vertical offset of the origin relative to the top edge, where a positive value points downwards.

In EGI 4.0, the overlay array holds up to 16 labels of overlays that can apply to a frame. When an element in this array is zero, this means "no overlay". The FLIC player chooses one of these overlays (or none) as the default overlay. Which overlay it chooses depends on the "overlay index" that one selects in the player. If the overlay index is zero, no overlay is displayed; if it is 1, the first overlay listed in the array is used, and so on.

EGI 3+
SCRIPT_CHUNK

EGI supports embedded run-time scripts in FLIC files that are written in the "pawn" language. The compiled P-code is added to the FLIC file. The format of the compiled P-code and an instruction reference can be found in the Small manual (available on-line as a PDF document on the Small language page mentioned earlier).

Specific functions in the run-time script execute on "events" in the FLIC animation, such as reaching the last frame of the segment (this is the frame before the ring frame). The currently defined event functions are:

 Function  Description
@FlicClose()Called when the animation is closed
@FlicFrame(framenumber)Called after each frame is decoded
@FlicLabel(label)Called when a label was reached
@FlicLastFrame()Called when the animation reaches its last frame of the current segment
@FlicLButtonDown(x, y)Called when the left mouse button is pressed in the animated frame
@FlicLButtonUp(x, y)Called when the left mouse button is released in the animated frame
@FlicOpen()Called when the animation is opened
@FlicPlay()Called when the animation is starts playing
@FlicRButtonDown(x, y)Called when the right mouse button is pressed in the animated frame
@FlicRButtonUp(x, y)Called when the right mouse button is released in the animated frame
@FlicSegment(segmentnumber)Called when a new segment has just started
@FlicStop()Called when the animation is stopped explicitly
EGI 1+
SEGMENT_TABLE
typedef struct {
  DWORD size;          /* Size of this chunk, including subchunks */
  WORD  type;          /* Chunk type: 0xF1FB */
  WORD  segments;      /* Number of SEGMENT chunks that follow */
} SEGMENT_TABLE;

If a segment table is present, it overrules the values in the header (number of frames, offsets to the first and second frames).

The segment table contains a series of SEGMENT chunks, one for every segment in the FLIC file. As of EGI version 4.0, the segment table also stores LABELEX chunks that hold symbolic names for the segments. The numeric value of each LABELEX chunk must match the (numeric) label of exactly one of the SEGMENT chunks. The name of the LABELEX chunk then gives the symbolic name for the segment.

EGI 1+
SEGMENT
typedef struct {
  DWORD size;          /* Size of this chunk (always 32 bytes) */
  WORD  type;          /* Subchunk type: 34 */
  WORD  label;         /* Label of the segment (user value) */
  BYTE  reserved1[2];  /* Reserved, set to zero */
  WORD  cont_image;    /* "continued from" image id */
  WORD  last_image;    /* id of the last image of this segment */
  WORD  flags;         /* Flags */
  WORD  frames;        /* Number of frames in the segment */
  DWORD oframe1;       /* File offset to frame 1 of the segment */
  DWORD oframe2;       /* File offset to frame 2 */
  WORD  next_segment;  /* segment number of segment to proceed with */
  WORD  repeat;        /* repeat count (0=indefinitely) */
  BYTE  reserved2[2];  /* Reserved, set to zero */
} SEGMENT;

The flags field contains four bit flags:

    Bit    Meaning
     0     the segment contains a ring frame
     1     the first frame contains a full image
     2     the "next_segment" field of the structure is valid
     3     audio must be synchronized with the animation

If bit 1 is set, the first frame contains either a full image, or a delta image plus a key image. In other words, bit 1 indicates whether the segment is a "launch point". See the EGI compiler instruction launch_point for more details.

The frames field does not include the ring frame (if a ring frame is present).

In a FLIC file has multiple segments and some of the segments are "continued" from other segments (see the compiler instruction continued_from), a frame may contain both a full image (the key image) and a delta image. The EGI player uses the cont_image and last_image fields to determine whether it can use the delta image (whose decoding is usually quicker than a full image), or whether it must decode the full image instead.

When creating the FLIC file, the EGI compiler assigns each picture a unique number. It stores the number of the last image in a segment in the last_image field of the SEGMENT structure. When you add a continued_from instruction to the segment, the compiler copies the last_image field of the segment that was specified in the continued_from instruction to the cont_image field of the current segment. The compiler then proceeds to create a delta image given the first image of the current segment and the last image of the "continued from" segment. A segment that is not continued from another segment has a value of 0xFFFF in the cont_image field.

The EGI player goes the opposite route. Assuming that the player just displayed the last frame of a segment, and at that moment you switch to another segment: if the last_image field of the current segment is the same as the cont_image of the next field, the player decodes the delta image of the new segment. Otherwise it decodes the key image.

EGI 1+
HUFFMAN_TABLE
typedef struct {
  DWORD size;          /* Size of this chunk */
  WORD  type;          /* Chunk type: 0xF1FC */
  WORD  codelength;    /* Maximum length of the Huffman codes */
  WORD  numcodes;      /* The number of codes */
  BYTE  reserved[6];   /* Must be set to zero */
  /* The following three fields are repeated "numcodes" times */
  WORD  code;          /* Huffman code */
  BYTE  length;        /* Length of the Huffman code */
  BYTE  value;         /* Byte value represented by the Huffman code */
} HUFFMAN_TABLE;

See the paper "EGI compression schemes" for information on the Huffman compression algorithm. This chunk is only present if bit 3 of the ext_flags of the FLIC file header is set.

all
FRAME_TYPE

This chunk is defined by Autodesk Animator, but Pro Motion and EGI extend it.

typedef struct {
  DWORD size;          /* Size of the chunk, including subchunks */
  WORD  type;          /* Chunk type: 0xF1FA */
  WORD  chunks;        /* Number of subchunks */
  WORD  delay;         /* Delay in milliseconds */
  short reserved;      /* Always zero */
  ushort width;        /* Frame width override (if non-zero) */
  ushort height;       /* Frame height override (if non-zero) */
} FRAME_TYPE;

The delay value overrules the speed field in the FLIC header; a value of zero indicates that the normal speed (from the FLIC header) applies. The delay field is an extension to the FLIC format, introduced by Cosmigo's Pro Motion.

The frame size override (width and height) is an EGI extension (starting with EGI 4.0). It is currently only used for overlays.

all
COLOR_256 & COLOR_64

The two subchunks with types 4 and 11 are identical, except that the range of the RGB values is 0-63 for COLOR_64 (type 11) and 0-255 for COLOR_256 (type 4). The 0-63 range of COLOR_64 reflects the 6-bit "CLUT" hardware for the original VGA card (sometimes referred to as the 18-bit DAC, where the 18-bits are divided into 3 channels).

The data in the chunk is organized in packets. The first word following the chunk header is the number of packets in the chunk. Each packet consists of a 1-byte skip count, a 1-byte copy count and a series of 3-byte RGB values (the "copy count" gives the number of RGB triplets). If the copy count is zero, there are 256 RGB triplets in the packet. For example, the data to change colours 2, 7, 8 and 9 would appear as:

    2                           /* two packets */
    2,1,r,g,b                   /* skip 2 entries, change 1 entry */
    4,3,r,g,b,r,g,b,r,g,b       /* skip 4, change 3 */

The FLIC file format assumes that when the palette changes, the entire frame is refreshed. Note that in a 256-colour FLIC file, pixel values are palette-indices. When the colour definition of a palette entry changes, all pixels with the corresponding palette entry must take over the new colour, regardless of whether they are refreshed in a DELTA_FLI or a DELTA_FLC chunk. Note that if your video hardware is physically in a palette mode (256-colours), this global colour refreshing is automatic. At the time that the FLIC format was developed, 256-colour palette-mode video cards were state-of-the-art for desktop PCs.

all
BLACK

All pixels in the frame have colour 0. This chunk has no data following the chunk header.

all
FLI_COPY

The data that follows the chunk header are the pixels of an uncompressed image of the frame. The number of pixels are exactly width×height of the frame. The first pixel is for the upper left corner of the frame.

Note that FLX files (15-bpp) use 2 bytes per pixel.

all
BYTE_RUN (FLI_BRUN)

The data following the chunk header is a full image that is compressed with byte oriented RLE. The first image of a segment and key frames are usually stored in a BYTE_RUN chunk.

Each line of the image is compressed separately, starting from the top of the image. The first byte of each line is the packet count. It is a holdover from the FLI format and it should be ignored, because it is now possible to have more than 255 packets on a line (for FLC files). Instead, the width of the frame image now is the criterion for decoding: continue decompressing until the number of uncompressed pixels becomes equal to the image width. However, some players still rely on this pack count, so FLIC compilers should still generate them and only set it to zero when the packet count indeed does exceed 255.

Each RLE packet consists of a count byte and one or more data bytes. If the count byte is negative, its absolute value is the number of data bytes (following the count byte) to copy to the image: a literal run. If the count byte is positive, the single data byte that follows must be replicated in the image "count" times: a replicate run.

all
DELTA_FLI (FLI_LC)

This chunk is used for FLI type files; the newer FLC format replaces this chunk with DELTA_FLC (see below). The chunk contains the differences (the "delta") between the current frame and the previous frame.

The first 16-bit word behind the chunk header is the line number (starting from the top of the image) for the first line in the image that differs from the previous frame. In other words, it is a line skip count. The second word is the number of lines in the chunk. The data for the lines themselves follow these two words.

Each line starts with a one-byte packet count for the line. Unlike the BYTE_RUN chunk, this value is significant because the "delta" need not to store the complete width of the frame image. The packets themselves follow the packet count. Each packet consists of a column skip count, an RLE count byte and zero or more data bytes. The column skip count is a one-byte value; it holds the number of pixels to skip (the number of pixels that did not change between the current frame and the previous frame) from the current position in the line. It can have a value of zero. The RLE count byte and the data bytes are similar to the BYTE_RUN encoding: if the count is positive, that number of bytes is to be copied from the data to the image (literal run); if the count is negative, its absolute value is the replication count of the one data byte that follows (replicate run).

Two pitfalls:

Also note that the "FLIC file format" document that originates from Autodesk mentions an extra byte that prefixes each line. This byte, the "starting x position of the data on a line", does not exist.

all
DELTA_FLC (FLI_SS2)

This chunk is similar to the DELTA_FLI chunk, but it compresses the delta image differently. The data following the chunk header is organized into lines and each line is organized into packets. Every line starts with one or more word-sized "opcodes".

The first word following the chunk header is the number of lines in the chunk. This count does not include "skipped" lines. Each line starts with one or more opcodes. One of the opcodes (the last) is the packet count. The highest two bits of the opcode word give its type:

  Bit 15   Bit 14   Description
    0        0      The opcode is the packet count for the line, it can be zero
    0        1      Undefined
    1        0      Store the opcode's low byte (bits 0-7) in the last pixel of the line
    1        1      The absolute value of the opcode is the line skip count

The RLE compression of DELTA_FLC is similar to that of DELTA_FLI, but it is word oriented. The first byte of each packet is the column skip count; the second byte is the RLE count byte. Zero or more data words follow the RLE count byte. If the count is positive, that number of words of data is copied to the image; if the count is negative, one data word follows and the absolute value of the count tells how many times that word must be replicated in the image.

The two pitfalls from the DELTA_FLI chunk apply here too (see above). Additionally:

all
PSTAMP
typedef struct {
  DWORD size;           /* Size of this chunk */
  WORD  type;           /* Chunk type: 18 */
  WORD  height;         /* Height of the postage stamp */
  WORD  width;          /* Width of the postage stamp */
  WORD  xlate;          /* Colour translation, always 1 */
} PSTAMP;

A "postage stamp" is a reduced image of the first frame of an animation. A postage stamp created by Autodesk Animator Pro has the preferred size of 100*63 (the actual size can vary) and uses a universal palette.

The palette is an RGB cube with 6 levels of each red, green and blue. This totals in 216 colours. An arbitrary RGB value (where each component is in the range of 0-255) is mapped into the six-cube space using:

((6*red)/256) * 36 + ((6*green)/256) * 6 + (6*blue)/256

The PSTAMP chunk embeds another chunk. This is usually a BYTE_RUN chunk or a FLI_COPY chunk (for compressed and uncompressed images respectively). If the type of the embedded chunk is 18 again (the type of PSTAMP is also 18), that chunk contains a 256-byte colour translation table. The translation table maps every palette index of the first frame to the universal six-cube colour space. To display the postage stamp, a program decodes the image of the first frame and maps every pixel of that image to the six-cube colour palette (using the translation table).

DTA, EGI 3+
DTA_BRUN, DTA_COPY and DTA_LC

These chunks are generated by the DTA program by Dave K. Mason for FLIC files with 15-bit, 16-bit or 24-bit colour depth, and by EGI starting with version 3.0. FLIC files with these formats usually have a .FLH or a .FLT extension. EGI supports only the 16-bit variety of these chunks.

In 24-bit FLIC files, pixels are made up of three bytes in the order B,G,R. In 16-bit files the colour values are packed into words (two-byte units) in "rrrrrggg gggbbbbb" format. 15-Bit FLIC files have pixels packed into the format "0rrrrrgg gggbbbbb". (The "blue" bits are in the lowest bit positions of each word.)

The DTA_BRUN chunk is numbered 25 (instead of 15 for a standard BYTE_RUN). The Repeat/Copy value is still a byte, but it refers to a number of pixels to copy or repeat, not bytes.

The DTA_LC chunk is numbered 27. Internally it is like chunk type 7 (DELTA_FLC). It starts with a number-of-lines value. For each line, the packet is a signed word value. If it is negative then it represents a lines-to-skip value and it does not count toward the number-of-lines. Each non-negative packet begins with a skip counter. This is still a byte, but it represents a number of pixels to skip, not bytes. Next comes a repeat/copy packet. It represents a number of pixels to copy or skip, not words. (Though in a 16-bit FLIC file, the pixels are words.)

The copy chunk is numbered 26, although the standard "copy" chunk type 16 (FLI_COPY) would do equally well: there is no decoding for copy chunks.

EGI 1+, EGI 4
LABEL, LABELEX
typedef struct {
  DWORD size;           /* Size of this chunk (usually 10) */
  WORD  type;           /* Chunk type: 31 */
  WORD  label           /* Label of the frame (user value) */
  BYTE  reserved[2]     /* Reserved, set to zero */
} LABEL;

typedef struct {
  DWORD size;           /* Size of this chunk */
  WORD  type;           /* Chunk type: 41 */
  WORD  label           /* Label of the frame (user value) */
  BYTE  reserved[2]     /* Reserved, set to zero */
  BYTE  name[variable]  /* symbolic name of the label */
} LABELEX;

The EGI API function FlicPlay() sends a notification message if it encounters a label subchunk in a frame. The message is sent (using either the Microsoft Windows function SendMessage() or using a direct callback) after decoding (and displaying) the frame. If the FLIC file has an embedded script, a label invokes the public function @FlicLabel() in the script.

A bug in early versions of the EGI player caused it to assume that LABEL chunks would always be exactly 10 bytes. Extending the label chunk with additional could therefore cause compatibility problems with those early players. Therefore, EGI defined a new, separate chunk for extended labels.

EGI versions as of version 4.0 store the symbolic name of a label (if any) in the chunk. The length of the name is the length of the chunk minus the fixed size of the chunk and minus any padding. The fixed size of the chunk is 10 bytes. The chunk is padded to an even size in bytes with zero bytes. So a label name like "eat" is stored as four characters 'e', 'a', 't' and '\0'. A label name like "walk" is stored in four characters, the string is not zero-terminated.

EGI 1+
KEY_IMAGE

For standard 256-colour FLIC files, the KEY_IMAGE chunk is the same as BYTE_RUN, but a frame that has a KEY_IMAGE chunk also contains a DELTA_FLC from a previous segment. A player can decide (based on the transition it makes from segment to segment) whether to decode the KEY_IMAGE and skip the DELTA_FLC, or to decode the DELTA_FLC and skip the KEY_IMAGE. See the SEGMENT chunk for more information.

For 16-bit FLIC files, the KEY_IMAGE chunk has the same encoding as DTA_BRUN. Similarly to the 256-colour FLIC files, the KEY_IMAGE chunk only appears in combination with a DTA_LC chunk.

EGI 1+
KEY_PAL

The same as COLOR_256, but it is only present for key images.

EGI 1+ & EGI 2+
BMP_MASK & MLEV_MASK

The chunk MLEV_MASK is defined as of EGI version 2.0; the chunk BMP_MASK exists since EGI 1.0.

The chunk starts (right after the chunk header) with four 16-bit words that give the bounding box of the mask. You can use this bounding box to speed up drawing operations, because you do not have to draw anything outside this box (all pixels are transparent outside the bounding box). The values are stored in the following order: x y width height.

The mask data starts behind the bounding box. Each line is encoded separately. A line starts with a "line skip count", which indicates how many lines remain unchanged from the previous mask. It is a two-byte value. It is zero for every line in a full mask.

The bitmap data (for the mask bitmap) comes after the line skip count. The bitmap data is compressed with the same RLE encoding as the BYTE_RUN image. This means that if the first (type) byte is positive, it is followed by a single pixel that must be replicated; if it is negative, it is followed by a series of bytes that must be copied literally. In contrast to the BYTE_RUN compression, no "packet count" byte is stored at the beginning of a scan line. Each scan line of the mask is compressed individually. Huffman and BWT compression do not apply to masks.

The data of a bitmap mask (after compression) is a 1 bit per pixel (8 pixels per byte) bitmap with the same size as the frame image. Each bit that is set ("1") represents a transparent pixel in the frame image. Each bit that is cleared ("0") represents an opaque pixel.

A multilevel mask is an 8 bits per pixel bitmap (with the same size as the frame image). Each byte in the mask represents the transparency level of the corresponding pixel in the frame image. A value of 255 is fully transparent, and 0 is fully opaque. In EGI version 2.x, you could actually use only two levels (0 and 255); as of EGI version 3.0, you can define up to 15 additional transparency levels.

Note that you can only specify the number of transparency levels; the opacity value of each level of the multilevel masks is not stored. The FLIC file format does not indicate the purpose the additional mask levels either. The number of transparency levels is in the transp_num field in the FLIC file header (EGI versions prior to 3.0 set this field to zero). The multilevel transparency masks were designed to be used with AniSprite, which allows you to set the opacity for each level (and lets you decide whether the additional levels are for "luma" masks or for "alpha" masks); please look up the AniSprite documentation for more information.

A frame can contain both a full image and a delta image. This occurs, for example when a segment in a FLIC file is both "continued_from" another segment and a launch point, or when the "key_frames" instruction is used. The mask for a frame that contains both a delta image and a full image is always a full mask.

See also the RGN_MASK chunk.

EGI 1+
REGION
typedef struct {
  DWORD size;           /* Size of this chunk */
  WORD  type;           /* Chunk type: 37 */
  WORD  number;         /* Number of rectangles that form the region */
  /* The following four fields are repeated "number" times */
  WORD  x;              /* Pixel coordinates of a rectangle */
  WORD  y;
  WORD  width;          /* Size of the region in pixels */
  WORD  height;
} REGION;

The EGI compiler stores the region of frame differences (see the dif_region instruction of the compiler's script language) by means of a grid. In the current release, the grid is composed of square tiles of 16*16 pixels. When a single pixel in a tile changes, all 256 pixels in that tile are flagged as "modified".

Two neighbouring tiles that are both flagged as "modified" are combined into a single new tile. The edges of the resulting rectangular tiles are always snapped to the grid points. Therefore, each rectangle in a region of frame differences needs not to enclose the object at pixel precision. However, no rectangle will exceed the bounding box of all differences between two frames.

The purpose of a coarse grid is to avoid a large amount of very small areas. The cost of the overhead for every call to the BitBlt() function for all these areas might be higher than the cost of blitting several pixels too many.

As of EGI version 2.0, the maximum number of tiles in a region is in the field max_regions in the FLIC file header.

EGI 2+
WAVE
typedef struct {
  DWORD size;          /* size of this chunk */
  WORD  type;          /* Chunk type: 38 */
  WORD  flags;
  WORD  samplefreq;    /* sample frequency */
  DWORD overlap;       /* sample overlap (in bytes) */
  BYTE  reserved[6];   /* always zero */
} WAVE;

The flags value is a bit field.

  Bit  Description
   0   Sample size is 16-bit (otherwise 8-bit)
   1   Format is signed PCM (otherwise unsigned PCM)
   2   Audio is stereo
   3   First block of the audio stream (open/reset sound card/driver)
   4   Last block of the audio stream (close sound card/driver)

The digitized audio data follows the chunk. The format depends on the various flags. If audio is 16-bit, there are two bytes per sample, in Little Endian (Intel format). In unsigned PCM, the "silence" level is 128 for 8-bit samples and 32768 for 16-bit samples. For stereo audio the samples for the left and right channels are interleaved; the sample for the left channel precedes the sample for the right channel.

Currently, EGI only supports 8-bit unsigned PCM or 16-bit signed PCM. These are the same formats as used in the .WAV and the .VOC file formats.

An audio stream is often be stored in a single block. The audio starts at the frame in which the block occurs, and it continues to "sound" during the displaying of the next frames. Audio and animation are not necessarily synchronized. For these single block audio streams, both bits 3 and 4 in the flags field are set, and overlap is always zero.

The audio stream can also be cut in various blocks. The first block contains enough samples to get from the current frame to the first key frame. The key frame contains another audio block with enough samples to get to the next key frame, etc. Here, the bits 3 and 4 of the flags field help to glue the blocks together to a sequential audio stream. Audio and animation should be synchronized to play back correctly. (The EGI player synchronizes animation and sound by default if the sound is cut into blocks.)

To avoid gaps in the audio when synchronization is not perfect, each block contains more samples than strictly necessary. In the current implementation, EGI adds enough samples to go to one frame after each key frame. When sending a (next) block to the audio device, you should ignore the first overlap bytes from the audio data.

You can jump in the middle of an animation, and this way, you can also jump in the middle of a multiple block audio stream. In this case, to get a proper synchronization, ignore the overlap field for the first audio block that you encounter.

EGI 2+
USERSTRING

A zero-terminated ASCII string follows the chunk header. The USERSTRING chunk allows an application to store general-purpose strings (both for copyright information as for references to other files or data) in a frame.

EGI 3.1+
RGN_MASK

The chunk starts (right after the chunk header) with four 16-bit words that give the bounding box of the mask (this is similar to the BMP_MASK and RGN_MASK chunks). The values are stored in the following order: x y width height.

The mask data starts behind the bounding box and consists of a list of non-overlapping rectangles. This set of rectangles describes the opaque region of the frame. Each rectangle is composed of four 16-bit words, again in the order x y width height. The number of rectangles in the region can be determined from the size of the chunk.

There is no delta encoding for a region mask, except that if a RGN_MASK chunk is absent from a frame it should be considered equal to the region mask of the previous frame.

Note that the REGION chunk contains a coarse region of changes between two frames. The RGN_MASK chunk is a region of opaque areas of a single frame and it is precise at pixel level.

See also the BMP_MASK and MLEV_MASK chunks.

EGI 4
SHIFT

Shift chunks are generated when the frame_shift() compression option is present in the EGI script. As noted in the manual, the frame shift compression is effective on animations where the background is panned or where objects move over a fixed background, and in particular objects that include transparency masks.

The shift chunks give pixel counts by which the scan lines in the current image must be shifted horizontally and/or vertically to better resemble the "next" image. There are separate shift chunks for the image and for the mask; only multilevel masks (the MLEV_MASK chunk) are applicable for frame shift compression. That is, if you have region masks, the mask cannot be frame-shifted, but the image in each frame can still benefit from frame shift compression.

The chunk header has the following format:

typedef struct {
  DWORD size;           /* size of this chunk */
  WORD  type;           /* Chunk type: 42 */
  BYTE  img_id;         /* image/mask identifier */
  BYTE  flags;          /* flags, reserved */
  WORD  prio_list;      /* size (in bytes) of the priority list */
} FRAMESHIFT;

The first after the fixed chunk header, img_id is zero if the frame shifts apply to the image and 2 if the frame shifts are for the (multilevel) mask. The following byte is for general purpose flags; it is currently always zero. The next 16-bit word, prio_list is the size (in bytes) of the "priority list", which is one of the three lists that follow the header.

Following the header are two lists with byte values and a third list with word values a variable-length encoding (technically, it is also a list of bytes). The first two lists have a length that is equal to the height of the frame, the length of the third list is in the header (described above). All three lists are compressed separately with the compression algorithm that is also used for the BYTE_RUN chunk.

The first list gives the vertical shifts and the second list gives the horizontal shifts. Each value in either of these two lists is a signed 8-bit number and indicates a shift count. The third list gives the order in which the shifts should be applied. It is variable length because only those lines for which the order is important are listed.

See the paper "EGI compression schemes" for details of the frame shift algorithm.

For animations that use frame shift compression, the maximum frame size is restricted to 16384 × 16384 pixels.

EGI 4
PATHMAP

The "path map" is a planning table that can tell you how to go from one segment to any other segment, while using only "known to be good" transitions. A FLIC that has segments has optional cont_image and last_image markers. When the cont_image marker of one segment matches the last_image marker of another segment, that indicates a fluent transition between the two. The path map forms a matrix of all such transitions so that the animation path from one segment to another segment is easy to look up.

The goal of the path map is to make "pose to pose" animation easier, especially when the next pose of the character is determined dynamically or interactively. When pursuing to go from one segment to another segment in a fluent manner, it may be necessary to go via one or more intermediate segments (transitions). The path map records the shortest fluent way to get from the "current" segment to any other segment.

The path map is a square matrix with a number of rows and columns that is equal to the number of segments. That is, the path map of an animation with 4 segments is a 4×4 matrix. Each entry in the path map is the segment segment number (a two-byte value) of the next segment to take, when using the current segment to index the matrix column and the desired "goal" segment to index the matrix row. When the value in a matrix cell is -1, no fluent transition is available: either there is no fluent path between the two segments, or you have already arrived at the goal segment.

As is apparent, one entry in the path map does not indicate a complete path, but only the next step to take to come closer to the goal segment. Once you arrive at that "next segment", you do another look-up and get a new "next step" that is closer to the desired goal segment (and so on). One row in the path map matrix does contain an entire path, by the way, but not in a sequential way. In fact, one row of the matrix contains all paths that lead to one destination segment.

 

Frequent errors

Unfortunately, several utilities create FLIC files that do not completely comply with the standard. Most FLIC players attempt to detect and silently correct these errors. Below is a list of frequent errors in FLIC files.

 

References

Kent, J.; "The FLIC File format"; Dr. Dobb's Journal, March 1992 (Volume 18, issue 3).
A description of the FLIC file format by the original creator of the Autodesk Animator software.
"EGI compression schemes".
An on-line paper with descriptions ans additional pointers to the extended compression schemes that EGI brings to the FLIC file format.