Vault-Tec Labs

Join the live chat in The Vault's IRC channel!
Also, don't forget to upload your custom art to the Custom Art Repository! (For help uploading, see Help:Uploading FRM files)

READ MORE

Vault-Tec Labs

This document is a work in progress based on the description and source code provided in the spr2gif utility written by ABel of TeamX. Spr2gif is written in Delphi (or a pascal variant?). However, here I will try to present the information in C style wherever possible.

I should point out that while I have written a loader that can parse all of the headers correctly, but I haven't yet implemented a decompression scheme needed for some .spr files, so my experience in some areas of this format is limited. I hope to document this page better once my loader is fully working.

It is my understanding that these sprites are not directly compatable with Fallout 1 & 2 because Fallout Tactics uses a different level orientation. Any effort to skew these images into a orientation suitable for Fallout 1 & 2 would result in a loss of quality (Bluring/Tearing).

Data types used in this document:[]

#define Uint32 unsigned       integer // (4 bytes)
#define Uint16 unsigned short integer // (2 bytes)
#define Uint8  unsigned       char    // (1 byte)
#define Sint32   signed       integer // (4 bytes)
#define Sint16   signed short integer // (2 bytes)
#define Sint8    signed       char    // (1 byte)

struct sString
{
    Uint32  length;
    char   *data;   // no '\0' at end
};

struct sPoint
{
    Uint32  x;
    Uint32  y;
};

struct sRect
{
    Uint32  x1; // left
    Uint32  y1; // top
    Uint32  x2; // right
    Uint32  y2; // bottom
};

Reading Strings:[]

in an .spr file, strings are stored in [pascal format?]. The string data is preceeded by a Uint32 containing the length of the string. There is no '\0' to terminate the string.


Sprite Header:[]

The sprite header is the first element in a .spr file. It is layed out as follows:

// SPR_HDR

Uint8  [ 11 ]          - '<sprite>' '\0' '4' '\0' - 11 bytes
Uint8  [  3 ]          - unknown 3 bytes
sPoint                 - centering coordinates
Uint8  [  3 ]          - unknown 3 bytes
Uint32   seq_count     - sequence count
SEQ_HDR[ seq_count ]   - sequence headers
Uint32   anm_count     - animation count
ANM_HDR[ anm_count ]   - animaion headers
IMG_HDR[ anm_count ]   - image headers

Sequence Header:[]

// SEQ_HDR

Uint32   itm_count     - item count
Sint16 [ itm_count ]   - if this value is >= 0, it is the number of the frame
                         in the ANM_HDR. values < 0 are unknown for now.
Uint32 [ itm_count ]   - unknown itm_count*4 bytes
sString                - sequence name
Uint16                 - ANM_HDR index containing the frames referenced by this
                         sequence.

Animation Collection Header:[]

// ANM_HDR

Uint8  [ 12 ]          - '<spranim>' '\0' '1' '\0'
Uint32                 - .spr file offset of the image data, relative to the
                         start of the .spr file.
sString                - animation collection name
Uint32   frm_count     - frame count
Uint32   dir_count     - directions per frame
RECT   [ frm_count *
         dir_count ]   - bounding boxes for each frame of each direction

Parsing Image data:[]

At this point all of the headers should be fully parsed and we can proceed to load the image data. Each of the ANM_HDR structures in the SPR_HDR contains an offset in the file to some image data. The actual image data itself comes after a small header. This header is required because the image data is sometimes compressed.

Uint8 [ 14 ]           - '<spranim_img>' '\0'
Uint16                 - if '1' '\0' - uncompressed
                       - if '2' '\0' - compressed

Note that '1' and '2' are ascii characters, not data values. '1' in decimal is 49, and '2' is 50.

Compressed Image Data:[]

if the data is compressed the the header will continue like so:

Uint32                 - data size after decompression
Uint8 [ ... ]          - raw, compressed image data

This is where the details get a little sparse since its not well documented, and im at this stage myself.

As far as I know there is no header entry to specify the size of the compressed data. Spr2Gif seems to infer the size of the compressed data by looking for the start of the next <spranim_img> entry and using the difference as the size.

Spr2Gif seems to use the ZLib library to 'inflate' the compressed data. I havent used ZLib before this project so until I can successfully decompress the image data there is not much more information I can provide. More information is availible by studying the source code for spr2gif.