-
Notifications
You must be signed in to change notification settings - Fork 6
Sprite sheet
Most sprite sheets are located at SUBDATA.DAT/START.DAT/ANM000.DAT
and each sprite sheets is made of 8 parts:
- Header + 4 data pointers
- Animations
- Layers
- Sprite sheets informations
- Keyframes
- Cutouts
- Color table
- Sprite sheet images
Type | Size | Description |
---|---|---|
uShort | 2 byte | Number of animations |
uShort | 2 byte | Number of layers |
uShort | 2 byte | Number of colortable sets? |
uShort | 2 byte | Number of sprite sheets |
uShort | 2 byte | Number of keyframes |
uShort | 2 byte | Number of cutouts |
uShort | 2 byte | Number of color tabels, is always 1? |
uShort | 2 byte | Number of sprite sheets? |
The four data pointers:
Type | Size | Description |
---|---|---|
uInt | 4 byte | Points to keyframes |
uInt | 4 byte | Points to cutouts |
uInt | 4 byte | Points to the color tables |
uInt | 4 byte | Points to the image data |
For each animations:
Type | Size | Description |
---|---|---|
uShort | 2 byte | Start keyframe index |
uShort | 2 byte | Animation ID (like a name) |
The end keyframe of an animation is the next animation starting keyframe.
A Layer is a set of cutouts, which get rendered in order.
For each layer:
Type | Size | Description |
---|---|---|
uShort | 2 byte | Start cutout index |
uShort | 2 byte | Number of cutouts |
At start there is a uInt (4 byte) with the size of the color table.
This contains the infomations about each sprite sheet. The width and height can be any number but the game matches them to the given power (2^x). So the sizes should be 16,32,64,128,256,512,1024 so on.
'The power of color table' determine the encoding of the ID sprite sheet. If the power is biger then 4 (16 colors) then each ID is saved as a uChar 1 byte.
For each sheet:
Type | Size | Description |
---|---|---|
uInt | 4 byte | Pointer to the image |
uShort | 2 byte | Width |
uShort | 2 byte | Height |
uChar | 1 byte | The power of color table |
uChar | 1 byte | image swizzled (not used on PC) |
uChar | 1 byte | The power of width |
uChar | 1 byte | The power of height |
For each Keyframe:
Type | Size | Description |
---|---|---|
uShort | 4 byte | Layer index |
uChar | 2 byte | Delay (ns?, s?) |
uChar | 2 byte | Type: 1 - Start, 0 - Continue, 2 - End (End keyframe is not displayed?), 3 - effect marker? |
uShort | 4 byte | ingame x offset? (mostly 0) |
uShort | 4 byte | ingame y offset? (mostly 0) |
Changed blinking keyframes, the delay has been increased and the end keyframe has been moved forward.
A cutout is a part of sprite sheet, which is build with a given color table.
For each cutout:
Type | Size | Description |
---|---|---|
uShort | 2 byte | External sheet ID, if not 0 then the keyframe references a outside file |
uChar | 1 byte | Sprite sheet index |
uChar | 1 byte | Color table offset |
Short | 2 byte | Anchor X, point of rotation and mirror |
Short | 2 byte | Anchor Y, point of rotation and mirror |
uShort | 2 byte | X |
uShort | 2 byte | Y |
uShort | 2 byte | Width |
uShort | 2 byte | Height |
Short | 2 byte | Scale X (0 - 100) |
Short | 2 byte | Scale Y (0 - 100) |
Short | 2 byte | Offset X, from the anchor point |
Short | 2 byte | Offset Y, from the anchor point |
Short | 2 byte | Rotation is degree |
uChar | 1 byte | Transparency (0-128) |
uChar | 1 byte | 0x10-Mirror horizontally, 0x08-Mirror vertically, 0x04 - Blend mode |
Left, 'scale X' was set from 100 to 50. Right, 'colortable index' was set from 0 to 2 (this color table is used for the character portrait).
The color table is build out if sets of 16 BGRA pixels. The size is 'size'*16*4
> Color table example.
The image data holds a offset to a color table value, to this is also added a starting offset, which is defined in the cutouts. This means to fully reconstruct the colors you also need to use the cutouts.
There are two known fromats:
16 or less colors:
This is the most common format, in which each byte holds two indexes for a color table => two pixels.
const char c = reader.readChar();
unsigned char index1 = c & 0x0F;
unsigned char index2 = (c >> 4) & 0x0F;
XKeeper custom sprite sheet. Left, the image IDs 0-32. Right, color image build with two separate color tables, one for the character and one for the portrait.
up to 256 colors:
Each byte is one offset. This is used if used color table has more then 16 colors.
/*
* colortabels - every color table as one long array
* cut - the cutout information
* cut.colortable - the colortable with cutout uses (start offset)
* IDImage - the 16 or 256 ID image (offset)
*/
rgbaImage[i] = colortabels[cut.colortable*16 + IDImage[i]];