These files primarily hold animations. However, they also hold some other static images which are not meant to be animated, but are, rather, simply need to be packaged together. For instance, fonts in Infinity Engine games are typically packaged in these files. As another example, most GUI controls have all of their supporting graphics packaged in BAM files, with, for instance, one frame representing the unpressed state of a button, one representing the pressed state, one for the selected state, and one for the disabled state. Note that a maximum of 255 cycles (animations) are supported. Since the fonts are stored with each character being a 'cycle', there are a maximum of 255 displayable chars in an infinity engine font. (i.e. the character 0xff does not have a representative in the font.
Overall structure
| Offset | Size (datatype) | Description |
|---|---|---|
| 0x0000 | 4 (char array) | Signature ('BAM ') |
| 0x0004 | 4 (char array) | Version ('V1 ') |
| 0x0008 | 2 (word) | Number of frames in this file |
| 0x000a | 1 (unsigned byte) | Number of cycles in this file |
| 0x000b | 1 (unsigned byte) | Transparent color index |
| 0x000c | 4 (dword) | Offset from start of file to frame entries (which are immediately followed by cycle entries) |
| 0x0010 | 4 (dword) | Offset from start of file to palette |
| 0x0014 | 4 (dword) | Offset from start of file to frame lookup table |
Several cycles may share the same frame. This is done by adding a layer of indirection. Instead of specifying which frames belong to a given cycle, each cycle has a list of frame indices.
| Offset | Size (datatype) | Description |
|---|---|---|
| 0x0000 | 2 (word) | Width of frame |
| 0x0002 | 2 (word) | Height of frame |
| 0x0004 | 2 (word) | X coordinate of center of frame |
| 0x0006 | 2 (word) | Y coordinate of center of frame |
| 0x0008 | 4 (dword) |
|
These entries refer to a range of indices in the frame lookup table, which in turn points to the actual frames. Note that entries in the frame lookup table can also be shared between cycles.
| Offset | Size (datatype) | Description |
|---|---|---|
| 0x0000 | 2 (word) | Number of frame indices in this cycle |
| 0x0002 | 2 (word) | Index into frame lookup table of first frame index in this cycle |
The palette is a standard array of 'RGBQUAD' structures, which means that the layout looks like:
BB GG RR 00 BB GG RR 00 BB GG RR 00 ... BB GG RR 00
Two possibilities for the purpose of the extra byte ('00') are that it is either the alpha component, always set to 0, or that, as is frequently the case with Windows programming via GDI, the extra byte could hold flags. (i.e. There is a flag that can be set in such entries under Windows to force it to treat the palette entry as a palette index instead of an RGB value.) In practice, it doesn't matter too much, since BG always runs in 16-bit or higher color mode, and doesn't use alpha transparency in its animations.
This is an array of frame indices. A cycle specifies a sequence of entries in this table. For instance, an animation might start at the 0th element
in this array, and travel over 6 frames. (The next animation, then, would typically start at the 6th element and run over some number of indices.) If
the first 6 entries in this table were { 0, 1, 1, 2, 3, 4 }, the animation would display frame #0, followed by frame #1 for two time periods, followed by
frames 2, 3, 4 in order. To find the number of entries in this lookup table, all you need to do is find the largest value of start+count in
the cycle entries table.
If this is not a compressed frame, then this is simply width*height bytes, which are pixel values using the palette specified earlier.
If this is a compressed frame, then a simple run-length-encoding scheme applies. The scheme is as follows:
x represents (x+1) copies of the transparent indexIf you are not familiar with run length encoding, it is a big win because most pixels in this type of image are transparent, and up to 256 transparent pixels in a row can by compressed down to 2 bytes. Most of the time transparent pixels appear in groups of 2 or more, so this compression scheme gains a lot.
Overall structure
The BAMC V1 data is an entire BAM V1 resource compressed with zlib and with a 12-byte header prepended, as seen below.
| Offset | Size (datatype) | Description |
|---|---|---|
| 0x0000 | 4 (char array) | Signature ('BAMC') |
| 0x0004 | 4 (char array) | Version ('V1 ') |
| 0x0008 | 4 (dword) | Uncompressed data length |
[ back to index ]