Animation File Format for PC Animate Plus (ANI)

Version 6.0

Last revised:  February 7, 1992

Bill Marsh
Presidio Software, Inc.

Scope.

The animation file format used by the animation programs from Presidio
Software is described in detail herein so software developers can write
compatible animation files. This description also promotes a better
understanding of the animation techniques used in these products.

Animation File Overview.

Animations consists of a series of pictures (called frames) which, when
shown in rapid succession, appear to have motion. Due to memory and
hardware limitations, the animation file does not store each of the frames.
It stores the first frame and the difference between each frame and the
next (called the delta). The animation file consists of four parts:

1. The animation header contains information about the animation file.

2. The initialization section contains the first frame and other data.

3. The animation section contains the deltas of the other frames and other
data.

4. The loop section contains the deltas from any loops in the animation.

5. The final section contains position information about all frames in the
animation.

Following the animation header, the remainder of the file is organized into
data 'chunks.' The first byte of each chunk is the chunk type. The length
of each chunk is determined by the chunk type and possibly other
information contained in the chunk itself.

This document describes version 6 of the animation file format.  The changes
from version 5 are a different animation file header and added data chunks.
Readers should be able to read the old and new formats.  Writers should only
write the new format.

The chunk types currently defined are:

Type    Definition
----    ----------
 00     Difference Chunk. This chunk contains data which describes the
difference (delta) between two frames. The length of this chunk varies
depending on the length of the delta and the video mode.  This type of
chunk is obsolete and should only be supported for playback, if at all.
Use chunk type 09, Compressed Difference instead (see below).

 01 End Frame. This chunk marks the end of the initialization section or the
end of a frame of data. This chunk is always one byte long.

 02     Palette Data. This chunk contains palette information used to set
or update the display palette. The length depends on the number of palette
entries.

 03     First Frame Data. This chunk marks the beginning of the first frame
picture. Data in the first frame is compressed, so the length of this frame
varies. This chunk is only found in the initialization section.  This chunk
also serves as the end marker of the initialization section.  If this chunk
is present, there will be no End Frame chunk.

 04     Frame Time. This chunk contains the number of vsync pulses to delay
before moving to the next frame. This chunk is always three bytes long.

 05     Sound File. This chunk defines the file name of a sound effects
file. The length of this chunk depends on the filename. This chunk is only
found in the initialization section.

 06     Sound Play. This chunk starts a sound effect. This chunk is always
3 bytes long.

 07     Volume Set. This chunk sets the volume and pan for a given sound
channel.  This chunk is always 4 bytes long.

 08     Not Used, reserved for future usage.

 09     Compressed Difference.  This chunk contains data which describes the
difference between two frames.  The length of this chunk varies depending on
the length of the delta and the video mode.  This is the new style
difference chunk and all future animations should be made with this
definition.

 10     Loop Definition.  This chunk defines a loop in the animation, either
a 'ping-pong' loop, or a 'run' loop, with the loop ending either by loop
count or events (key press, mouse button press, or external event).  The
basic chunk length is 4 bytes.  If a loop count is used, an extra 2 bytes
are added.  If the loop type is a 'run' loop, an additional 2 bytes are
added.

 11     External Event Trigger.  This chunk specifies an external event is
to be triggered during playback.  This chunk is always 2 bytes long.

 12     Frame Info.  This is a special data chunk which follows the last
loop frame.  This chunk contains the starting offsets of each frame
(including all loop frames) from the beginning of the animation file.  This
position is also given in the file header to enable readers fast access to
frame data.

 13     Repeated Sound.  This chunk is like the sound play chunk (06),
except that is has a repeat count to repeat the sound a given number of
times.  This chunk is always 4 bytes long.

 14     File Memo.  This chunk contains an ASCII string which can mean
anything the creating application wants it to.

A full description of the animation header and each chunk type and its data
follows.

Data Formats.

The animation file consists of bytes, words, and double words, in addition
to the animation header structure. In all cases, standard Intel byte and
word ordering is used: Least significant byte is in the first (least)
position: Least significant word is in the first (least) position.

Animation Header.

The animation header consists of information necessary for the playback of
the animation. The format of the header is given by the 'C' structure
below.

typedef struct {
	unsigned short  magic;          /* Animation Header Magic Number*/
	unsigned char   mode;           /* Mode animation was recorded  */
	unsigned char   vers;           /* Animation version number     */
	unsigned short  playback;       /* Preferred Playback Flags     */
	unsigned short  time;           /* Time constant for display    */
	unsigned short  frames;         /* Number of frames in animation*/
	unsigned short  loops;          /* Number of loop frames        */
	unsigned short  width;          /* Width of animation           */
	unsigned short  height;         /* Height of animation          */
	unsigned short  colors;         /* Number of colors in animation*/
	long            length;         /* Length (in bytes) of data    */
	long            frame_info;     /* File offset to frame info    */
} ANI_HEADER;

Member    Usage
------    -----
magic     Identifies the file as an animation file. The value, 0x4E41,
makes the ASCII letters 'AN'. This should be checked by any animation
player to make sure the indicated file is actually an animation file.

mode    Video mode in which the animation was recorded. For the Presidio
software products the available modes are listed in the following table:

      PC Animate   Resolution
      ----------   ----------
	5          640 x 350 x 16
	7          320 x 200 x 256
	11         640 x 480 x 16
	13         VESA 640 x 400 x 256 Color
	14         VESA 640 x 480 x 256 Color
	15         VESA 800 x 600 x 16 Color
	16         VESA 800 x 600 x 256 Color
	17         VESA 1024 x 768 x 16 Color
	18         VESA 1024 x 768 x 256 Color
	19         VESA 1280 x 1024 x 16 Color
	20         VESA 1280 x 1024 x 256 Color
	21         TARGA 256 x 256 x 32K Color
	22         TARGA 512 x 256 x 32K Color
	23         TARGA 512 x 512 x 32K Color
	24         HiColor 320 x 200 x 32K Color
	25         HiColor 640 x 400 x 32K Color
	26         HiColor 640 x 480 x 32K Color
	27         HiColor 800 x 600 x 32K Color
	28         HiColor 1024 x 768 x 32K Color
	29         HiColor 1280 x 1024 x 32K Color

vers            Animation File Format version. Currently, this version
number is 6. All animation readers should check this number to make sure the
version of the animation file is correct, so that the reader will not
encounter data streams that it doesn't understand.

playback        Preferred playback mode.  This member tells the reader which
mode of playback is preferred for this animation.  The encoding is divided
between the looping mode, and the starting flags for the animation.  The
definitions of the member is as follows:

	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
	| 15| 14| 13| 12| 11| 10| 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
	  |   |   |                                               |   |
	  |   |   Leave Last Frame                                +-+-+
	  |   Hide First Frame                                      |
	  Auto-Start Animation                                  0  Loop
								1  Ping Pong
								2  Once
								3  Forward Only

All other bits (2-12) are not used at this time and should be set to zero.

A Forward Only animation file does not use XOR pixels, but rather stores the
actual new value for the pixel.  These animations may not be played
backwards or have ping-pong loops in them.

time            Initial frame time. This number represents the number of
vertical sync pulses should be counted before proceeding to the next frame.
This value is only the default value and, while playing, individual frames
can have their own specific values (See the FRAME TIME data chunk)

frames          The count of animation frames stored in the animation. There
are actually more frames stored in the file, the extra being the "loop
frames." Readers should use this value to determine when to stop reading the
animation file. Simply using the End-Of-File is insufficient because some
file transport protocols, like XMODEM, pad the end of file with garbage data.

loops           The count of loop frames stored in the animation.  Readers
should use this value to determine when to stop reading the animation file.

width           The width in pixels of the animation file.  This can be
smaller than the resolution permits.

height          The height in pixels of the animation file.  This can be
smaller than the resolution permits.

colors          The number of colors in the animation file.  This can be
smaller than the resolution permits.

length  Number of bytes in the animation file after the initialization
information until the frame information. This is used by the animation
player to allocate memory to hold the animation data.

frame_info      Offset in the file to the location of the frame info data
chunk.  This chunk must follow the last loop delta.

Old Animation Header.

Prior to version 6, the animation header consisted of the following header:

typedef struct {
      unsigned short    magic;    /* Animation Header Magic Number */
      unsigned char     mode;     /* Mode animation was recorded */
      unsigned char     vers;     /* Animation version number */
      unsigned short    time;     /* Time constant for display */
      unsigned short    frames;   /* Number of frames in animation */
      long              length;   /* Length (in bytes) of data */
} OLD_ANI_HEADER;

Member    Usage
------    -----
magic     Identifies the file as an animation file. The value, 0x4E41,
makes the ASCII letters 'AN'. This should be checked by any animation
player to make sure the indicated file is actually an animation file.

mode    Video mode in which the animation was recorded. For the Presidio
software products the available modes are listed in the following table:

      PC Animate   Resolution
      ----------   ----------
	5          640 x 350 x 16
	7          320 x 200 x 256
	11         640 x 480 x 16

vers      Animation File Format version. Currently, this version number is
5. All animation readers should check this number to make sure the version
of the animation file is correct, so that the reader will not encounter
data streams which it doesn't understand.

time      Initial frame time. This number represents the number of vertical
sync pulses should be counted before proceeding to the next frame. This
value is only the default value and, while playing, individual frames can
have their own specific values (See the FRAME TIME data chunk)

frames    The count of animation frames stored in the file. There are
actually 'frames + 1' frames of information in the file, the extra being
the "loop frame." Readers should use this value to determine when to stop
reading the animation file. Simply using the End-Of-File is insufficient
because some file transport protocols, like XMODEM, pad the end of file
with garbage data.

length    Number of bytes in the animation file after the initialization
information. This is used by the animation player to allocate memory to
hold the animation data.

Animation Chunk Descriptions.

The following sections describe in detail the format of the chunk data
types currently used in animation files. The chunk descriptions detail the
information which follows the chunk type.

End Frame Chunk (Type 01).

The end frame chunk marks the end of a frame of data or the end of the
initialization section of the animation file. It consists of only one
byte.

  +--------+
  |  0x01  |    End Frame Chunk Type.
  +--------+

Palette Chunk (Type 02).

The palette chunk contains a new palette to be used in the current
animation. This chunk can be located either in the initialization section
or the animation section of the animation file. When located in the
initialization section it establishes the palette for the animation. When
located in the animation section, it changes the palette for the current
frame, and remains in effect until changed by another palette chunk. The
palette chunk is only used for video modes which use a palette. The palette
chunk is not used for animations which use the 32K color video mode. The
format of a palette chunk is as follows:

  +--------+
  |  0x02  |    Palette Chunk Type.
  +--------+
  |  Size  |    Number of Palette Entries. If 0, 256 are used.
  +--------+
  |  Red   |    Red, Green, Blue triplets follow for each palette
  +--------+    entry given above. Palette data always starts at
  | Green  |    color index #0. Each color component is left
  +--------+    justified in the byte.
  |  Blue  |
  +--------+
  |  etc.  |

First Frame Chunk (Type 03).

The first frame chunk contains the picture information for the first frame.
This chunk type can only be found in the initialization section of the
animation file. The picture is stored using a run-length-encoded
compression known as 'Pack-Bits'. This method was chosen due to the ease of
encoding and decoding the information. Each row is compressed separately,
thus allowing a simple test for errors (each row should expand to exactly
one row of pixels). The data, when compressed, is organized in bytes for
video modes with 256 or less colors, or short words for video modes with
32768 colors. The format of the chunk is as follows:

  +--------+
  |  0x03  |             First Frame Chunk Type.
  +--------+--------+
  | Number of Cols. |    Number of Pixel Columns.
  +-----------------+
  | Number of Rows  |    Number of Rows.
  +-----------------+

After this header, the data is organized into a stream of bytes or words,
depending on the video mode as described above. Data is organized into runs
of the same pixels or runs of unique pixels, determined by the value
specified by the first data item, the count. If the count byte is less than
128, then the run is of unique pixels of that length. If the count is
greater than 127, then the run is of duplicated pixels, each equal to the
next data item.

Here is an example of a decoder (for 16 or 256 color mode). The only
difference for a 32768 color mode is that the data being read should be
short words rather than bytes.

int              cols, rows, xx;
unsigned char    *buf, *pixel, data;
unsigned         count;

cols = getword();        /* read the number of columns */
rows = getword();        /* read the number of rows */

buf = malloc(cols);      /* Allocate space for row storage */

for( ; rows > 0; rows--) {
      xx = cols;
      pixel = buf;

      while(xx > 0) {
	    count = getbyte();
	    if(count > 128) {
		  count |= 0xFF00;        /* extend sign */
		  count = -count + 1;     /* correct length */
		  data = getbyte();

		  while(count-- > 0) {
			*pixel++ = data;
			xx--;
		  }
	    } else {
		  count++;
		  while(count-- > 0) {
			*pixel++ = getbyte();
			xx--;
		  }
	    }
      }

      if(xx < 0) {
	    /*      Error, too many bytes read in! */
      }

      /* Write data to screen here */
}

Difference Chunk (Type 00).

This data chunk is obsolete.  It is included here for compatibility purposes
only. New applications should support it for playback only, if at all. New 
animations should be written with the Compressed Difference Chunk (Type 09).

The difference chunk contains the data which is different between two
frames. This data chunk should only be located in the animation section or
the loop section of the animation file, and it must be the last chunk type
of the frame. This data is stored as the XOR of the pixels in the two
frames, thus forward and reverse playback is possible. Each difference chunk
contains pixels from the same row of pixels, no difference chunk crosses
into another row. There can be more than one difference chunk describing
changes to the same row of pixels.  Also, it is best to combine runs of
differences using XOR pixels of value 0 between runs, if the number of
pixels is less than the number of bytes in the difference chunk header. This
will reduce the number of difference chunk headers, saving space in the
animation file.

The chunk has a screen offset and a count of pixels in the chunk, followed
by a video mode specific data stream containing the XOR pixels. The offset
portion is a long word indicating an offset into screen memory, to the byte
where the difference begins (For 16 color mode, the actual 'pixel' offset
is used instead, to indicate which pixel, odd or even, is first changed).
The count is a short word specifying the number of pixels to change. XOR
pixels are packed into bytes for 16 color modes, with the first pixel
located in the lower nybble (bits 0-3) and the second pixel located in the
upper nybble (bits 4-7). For 256 and 32768 color mode, the pixels are
loaded into bytes or words, respectively. The format of the chunk is as
follows:

  +--------+
  |  0x00  |    Difference Chunk Type.
  +--------+--------+-----------------+
  |  Offset into Screen Memory        |    Offset to Pixel.
  +-----------------+-----------------+
  | Count of Pixels |    Count of Pixels.
  +-----------------+
  | XOR Pixels      |    XOR Pixels
  +-----------------+    (16 bit shown, 32K color)
  | etc.            |

Frame Time Chunk.

The frame time chunk represents the number of vsync pulses to display the
current frame. This value overrides the value located in the animation
header if present, and remains in effect until changed by another frame time
chunk. This chunk should only be located in the animation section of the
animation file. A frame time chunk value of 0 is a pause; the animation does
not proceed until the left mouse button is clicked or the Spacebar is
pressed. New animations should use the Loop Definition Chunk to encode a
pause, as this new chunk has many more options for terminating a pause.  The
format of the chunk is as follows:

  +--------+
  |  0x04  |    Frame Time Chunk Type.
  +--------+--------+
  |  Vsync Count    |    Frame Delay Time.
  +-----------------+

Sound File Chunk.

The sound file chunk contains the filename of a sound effect file. This
file is then loaded and made available for playback when triggered be a
sound play chunk. This chunk can only be located in the initialization
section of the animation file. The sound file is assumed to be located in
the same directory as the animation file. The format of the chunk is as
follows:

  +--------+
  |  0x05  |    Sound File Chunk Type.
  +--------+
  | Index  |    Sound Index Number.
  +--------+
  |  name  |    File Name, with a null character (0x00)
  +--------+    termination.
  |  ...   |
  +--------+    (Max of 13 bytes including the null)
  |  0x00  |
  +--------+

Sound Play Chunk.

This data chunk is obsolete.  It is included here for playback purposes
only.  And new animations should be written using the Repeated Sound Play
Chunk.

The sound play chunk signals the playback of a sound effect. It contains
the playback channel to use and the sound index number of the sound effect.
This chunk can be located in the initialization section or the animation
section of the animation file. The format of the chunk is as follows:

  +--------+
  |  0x06  |    Sound Play Chunk Type.
  +--------+
  |Channel |    Sound Channel to play sound effect on.
  +--------+
  |Sound ID|    Sound Index of sound effect to play.
  +--------+

Volume Set Chunk.

The volume set chunk sets the volume of a sound channel. It contains the
channel to set, the value to set for the volume, and the value to set for
the pan. This value remains in effect until changed by another volume set
chunk. This chunk can be located in the initialization section or the
animation section of the animation file. The format of the chunk is as
follows:

  +--------+
  |  0x07  |    Volume Set Chunk Type.
  +--------+
  |Channel |    Sound Channel to set volume.
  +--------+
  | Volume |    Volume value. 0 = minimum, 255 = maximum.
  +--------+
  |  Pan   |    Pan value. 0 = Left, 255 = Right.
  +--------+

Compressed Difference Chunk.

The compressed difference chunk contains the data which is different between
two frames. This data chunk should only be located in the animation section
or the loop section of the animation file, and it must be the last chunk type
of the frame. This data is normally stored as the XOR of the pixels in the
two frames, thus forward and reverse playback is possible.  If the forward
only playback mode is selected, the data is stored as the pixels from the
forward frame only, so no XOR is necessary, and the animation can not be
played backwards.

The ddifference is organized in a line-by-line basis, with a count of the
number of skip-difference packets, followed by the actual packets
themselves.  If the count of packets is negative, the absolute value of the
count is the number of lines to skip until the next change.  If the count of
packets is zero, it is the end of all delta information for this frame.

The skip-difference packets consists of an unsigned single byte skip count,
followed by a single byte difference count, followed by a variable number of
XOR pixels.  If the difference count is negative, it is followed by one XOR
pixel which is repeated the absolute value of the count times.  There is
only one compressed delta chunk per frame.

  +--------+
  |  0x09  |    Compressed Delta Chunk
  +--------+--------+
  |  Packet Count   |   Packet Count
  +--------+--------+
  |  Skip  |            Count of Pixels to skip.
  +--------+
  |  Diff  |            Count of Differences.
  +--------+
  |   XOR  |            XOR Pixels
  +--------+
  | etc... |
  +--------+--------+
  |  Packet Count   |   Packet Count, etc.
  +--------+--------+
  | etc... |

Loop Definition Chunk.

The loop definition chunk defines a loop in the animation.  This loop can be
either a 'run' loop or a ping-pong loop.  In all cases, the loop must be
twords the beginning of the animation from the current frame, or magical and
unexpected things may occur!

The chunk defines a frame which is looped to (or twords in the case of a
ping-pong loop), and a situation which will break out of the loop.  This
loop break can be a specified loop count, an external event, key press, or
mouse click.

  +--------+
  |  0x0A  |    Loop Definition Chunk
  +--------+--------+
  |      Flags      |   Loop Flags.
  +--------+--------+
  | Loop Target Frm |   Frame Target.
  +--------+--------+
  |  Loop Frame No. |   Loop Frame to use ('run' loop only)
  +--------+--------+
  |   Loop Count    |   Loop Count (if present)
  +--------+--------+

  Loop Flags:

    BIT 0 -- Run/Ping Pong Select.  If 0, selects a 'ping-pong' loop.  If 1,
selects a 'run' loop, and specifies that a loop frame number will be present
in the chunk.

    BIT 1 -- Break on Loop Count.  If 1, it uses a loop count to stop the
loop, and specifies that a loop count will be present in the chunk.

    BIT 2 -- Break on Left Mouse Click.  If 1, will break out of the loop
when the left mouse button is pressed.

    BIT 3 -- Break on Enter key press.  If 1, will break out of the loop
when the Enter key is pressed.

    BIT 4 - 14 -- Break on External Event.  External Events are defined by
the player.

    BIT 15 -- Reserved.  Should always be zero.

  Note:  Bits 1 through 14 can be combined to form an 'OR' condition.
For example, if bits 2 and 3 are both set, the loop will break if either a
left mouse click or enter key is pressed.  If bit 1 is set also, it will loop the maximum
times waiting for the enter key press or mouse click.  If only bits 4 - 15
are set, the player may interpret this as bits 2 and 3 set.  If no condition
bits are set, it is an unconditional loop.

  Note:  To cause a Pause, set the frame target to the current frame, select
a 'ping-pong' style loop, and set the flags depending on the method you wish
to exit the pause.  This allows better selection of controls than using the
frame time.  If a 'count' is given, this sets up a maximum time to wait for
the external event, basically a (count * frame time) amount of time.  In
this case only, the player should not accept an unconditional loop.  If no
bits are set, the player should assume that bits 2 and 3 are set.

External Event Trigger Chunk.

The external event trigger chunk causes the reader to trigger a reader
defined external event.  This can be used to trigger other peripherals.

  +--------+
  |  0x0B  |    External Event Trigger Chunk.
  +--------+
  | Event  |    Event number to trigger.
  +--------+

Frame Info Chunk.

The frame info chunk defines the offsets of all frames in the animation
file.  This can be used by readers to quickly locate the beginning of any
frame in the animation file.  The length of this chunk is determined by the
number of frame and loop deltas in the animation.  This chunk follows the
last loop delta at the end of the animation file, and it's offset in the
file is also contained in the header.  The length of each frame can be
calculated from the next frames offset (use the frame info chunk offset in
the header for the last loop frame length).

  +--------+
  |  0x0C  |    Frame Info Chunk.
  +--------+--------+--------+--------+
  |       Frame 1 Delta Offset        | Offset to frame 1 (32 bits)
  +--------+--------+--------+--------+
  |       Frame 2 Delta Offset        | Offset to frame 2 (32 bits)
  +--------+--------+--------+--------+
  |       etc...                      |
  +--------+--------+--------+--------+

Repeated Sound Play Chunk.

The sound play chunk signals the playback of a sound effect multiple times.
It contains the playback channel to use and the sound index number of the
sound effect.  This chunk can be located in the initialization section or
the animation section of the animation file. The format of the chunk is as
follows:

  +--------+
  |  0x0D  |    Repeated Sound Play Chunk Type.
  +--------+
  |Channel |    Sound Channel to play sound effect on.
  +--------+
  |Sound ID|    Sound Index of sound effect to play.
  +--------+
  | Count  |    Number of times to play sound.
  +--------+

Animation Memo Chunk.

The animation memo chunk contains a NULL terminated ASCII string.  This
string can contain up to 42 bytes of data plus one byte of NULL termination.
This chunk can only be located in the initialization section of the
animation file.  The format of this chunk is as follows:

  +--------+
  |  0x0E  |    Animation Memo Chunk Type.
  +--------+
  | String |    ASCII string, with a null character (0x00)
  +--------+    termination.
  |  ...   |
  +--------+    (Max of 43 bytes including the null)
  |  0x00  |
  +--------+

