DO/Updated Sprite Format

From Dark Omen Wiki

< DO(Difference between revisions)
Jump to: navigation, search
(Overall Structure)
(2. Frame Compression)
 
(24 intermediate revisions not shown)
Line 3: Line 3:
The overall structure of a sprite file looks a like this (in this order):
The overall structure of a sprite file looks a like this (in this order):
-
  SPRITE FILE HEADER (32 bytes)
+
  SPRITE FILE HEADER <size=32>
   
   
-
  FRAME HEADER 1
+
  FRAME HEADER 1 <size=32>
-
  FRAME HEADER 2
+
  FRAME HEADER 2 <size=32>
  .
  .
  .
  .
-
  FRAME HEADER number of frames
+
  FRAME HEADER (number of frames) <size=32>
   
   
-
  PALETTE ENTRY 1
+
   
-
  PALETTE ENTRY 2
+
COLOUR TABLE ENTRY 1 <size=4>
 +
  COLOUR TABLE ENTRY 2 <size=4>
  .
  .
  .
  .
-
  PALETTE ENTRY number of palette entries
+
  COLOUR TABLE ENTRY (number of colour table entries) <size=4>
   
   
   
   
-
  FRAME 0 DATA
+
  FRAME 1 DATA <size='''varies'''>
-
  FRAME 1 DATA
+
  FRAME 2 DATA <size='''varies'''>
  .
  .
  .
  .
-
  FRAME number of frames DATA  
+
  FRAME (number of frames) DATA <size='''varies'''>
For a description of each part, see below.
For a description of each part, see below.
Line 32: Line 33:
  struct SpriteFileHeader
  struct SpriteFileHeader
  {
  {
-
     char ID[4];           // = 'WHDO'
+
     char ID[4];             // = 'WHDO'
-
     int  filesize;         // = the size of the file in bytes
+
     int  filesize;           // = the size of the file in bytes
-
     int  version?;         // = 32
+
     int  frameHeadersOffset; // = file offset to beginning of the frame headers (=32)
-
     int  frameDataOffset   // = file offset to beginning of the frame data
+
     int  frameDataOffset     // = file offset to beginning of the frame data
-
     int  paletteDataOffset // = file offset to beginning of the palette data
+
     int  colourTableOffset  // = file offset to beginning of the palette data
-
     int  paletteEntryCount // = the total number of palette entries (*)
+
     int  colourTableEntries  // = the total number of colours in the colour table (1)
-
     int  paletteCount     // = how many unique palettes exist in this sprite
+
     int  paletteCount       // = how many unique palettes exist in this sprite
-
     int  frameCount       // = the number of frames of animation in this sprite   
+
     int  frameCount         // = the number of frames of animation in this sprite   
  }
  }
-
(* This is the total number of colours stored in the file, each of which belongs only to one palette.  e.g. there may be 300 colours stored in the file, spread throughout 5 different palettes; the paletteEntryCount is 300, the paletteCount is 5 )
+
==1. Number of palette entries==
 +
This is the total number of colours stored in the file, each of which belongs only to one palette.  e.g. there may be 300 colours stored in the file, spread throughout 5 different palettes; the colourTableEntries is 300, the paletteCount is 5 )
-
=Frame Header=
+
=Frame Headers=
There is one frame header for each animation frame in the sprite:
There is one frame header for each animation frame in the sprite:
Line 51: Line 53:
  {
  {
       byte frameType;        // see table below (1)
       byte frameType;        // see table below (1)
-
       byte compressionType;  // 0: not compressed, 1: packbits, 2: unknown (2)
+
       byte compressionType;  // see table below (2)
       short colourCount;    // = the number of unique colours in the frame
       short colourCount;    // = the number of unique colours in the frame
       signed short X;        // = X position of this frame
       signed short X;        // = X position of this frame
Line 60: Line 62:
       int compressedSize;    // = length of the compressed frame data
       int compressedSize;    // = length of the compressed frame data
       int uncompressedSize;  // = length of the uncompressed frame data
       int uncompressedSize;  // = length of the uncompressed frame data
-
       int paletteDataOffset; // = offset into the palette data
+
       int colourTableOffset; // = position of the palette for this frame in the ColourTable
-
       int unknown;          // = 0
+
       int padding;          // = 0
  }
  }
Line 68: Line 70:
:{|class="wikitable"  
:{|class="wikitable"  
! Type !! Description
! Type !! Description
 +
|-
 +
| 0 || This frame is a repeat of a previous frame
 +
|-
 +
| 1 || Flip Horizontally
 +
|-
 +
| 2 || Flip Vertically
 +
|-
 +
| 3 || Flip Horizontally and Vertically
|-
|-
| 4 || This is a normal frame.
| 4 || This is a normal frame.
Line 81: Line 91:
| 0 || Uncompressed - the frame data consists of 1 byte indices in to the associated palette
| 0 || Uncompressed - the frame data consists of 1 byte indices in to the associated palette
|-
|-
-
| 1 || Packbits - the frame is compressed using the 'packbits' compression scheme
+
| 1 || Packbits - the frame is compressed using the [http://en.wikipedia.org/wiki/Packbits PACKBITS] compression scheme.
|-
|-
-
| 2 || Unknown - the frame is compressed using an unknown compression algorithm
+
| 2 || Zero Runs - the frame is compressed using the scheme detailed below
|}
|}
 +
 +
=== Zero Runs Compression ===
 +
 +
The algorithm for this method is as follows:
 +
# Read a signed byte (we'll call this 'op')
 +
# If the byte is < 0 then write -op 0s to output
 +
# Otherwise, write op+1 literal bytes to output
 +
# Go to step 1
==3. Offset Into the Frame Data==
==3. Offset Into the Frame Data==
-
This offset is into the '''frame data'''.  i.e. this frame's data is at SpriteHeader.frameDataOffset + FrameHeader.dataOffset
+
This offset is into the '''frame data'''.  i.e. this frame's data is at SpriteHeader.frameDataOffset + FrameHeader.dataOffset and goes on to SpriteHeader.frameDataOffset + FrameHeader.dataOffset + FrameHeader.compressedSize
 +
 
 +
=Colour Table=
 +
 
 +
Each colour is stored as follows:
 +
 
 +
struct Colour
 +
{
 +
      byte blue;
 +
      byte green;
 +
      byte red;
 +
      byte padding; // =0 not used
 +
}
 +
 
 +
The number of colours in the table is stored in the file header, and palettes are made up of entries from this data
 +
 
 +
=Frame Data=
 +
 
 +
This part of the file consists of all of the (potentially compressed) colour indexed data for each frame.  To separate it, you must know the start in the buffer and size of each frame as listed in the frame headers.
 +
 
 +
=Important Notes=
 +
 
 +
Unit sprites have a few specific properties.
 +
 
 +
* They are uncompressed
 +
* They only use 16 colours per palette. 
 +
* Colours with each component < 8 will be transparent in-game; to use black in a sprite it is necessary to use RGB=(8,8,8).
 +
* Cyan, RGB=(0,255,255) is used to represent the unit shadow.
 +
* The frames are arranged with a stride of eight, for different directions follow on from the previous direction.  e.g. the frames might be WALKING1_NORTHEAST, WALKING1_EAST, ... , WALKING1_NORTH,  WALKING2_NORTHEAST, WALKING2_EAST ... WALKING2_NORTH etc.  '''Note:''' some artillery units are the exception, since they have 16 directions; they have a corresponding stride of 16.
 +
* The game likely maps actions to frames using a Unit Type listed in the ARM file.  All 'monsters' for example seem to have the same mapping.
 +
 
 +
[[category:Modifications]]

Current revision as of 17:15, 4 June 2012

Contents

Overall Structure

The overall structure of a sprite file looks a like this (in this order):

SPRITE FILE HEADER <size=32>

FRAME HEADER 1 <size=32>
FRAME HEADER 2 <size=32>
.
.
FRAME HEADER (number of frames) <size=32>


COLOUR TABLE ENTRY 1 <size=4>
COLOUR TABLE ENTRY 2 <size=4>
.
.
COLOUR TABLE ENTRY (number of colour table entries) <size=4>


FRAME 1 DATA <size=varies>
FRAME 2 DATA <size=varies>
.
.
FRAME (number of frames) DATA <size=varies>

For a description of each part, see below.

Sprite File Header

The file header consists of the first 32 bytes of the file

struct SpriteFileHeader
{
    char ID[4];              // = 'WHDO'
    int  filesize;           // = the size of the file in bytes
    int  frameHeadersOffset; // = file offset to beginning of the frame headers (=32)
    int  frameDataOffset     // = file offset to beginning of the frame data
    int  colourTableOffset   // = file offset to beginning of the palette data
    int  colourTableEntries  // = the total number of colours in the colour table (1)
    int  paletteCount        // = how many unique palettes exist in this sprite
    int  frameCount          // = the number of frames of animation in this sprite   
}

1. Number of palette entries

This is the total number of colours stored in the file, each of which belongs only to one palette. e.g. there may be 300 colours stored in the file, spread throughout 5 different palettes; the colourTableEntries is 300, the paletteCount is 5 )

Frame Headers

There is one frame header for each animation frame in the sprite:

struct FrameHeader
{
     byte frameType;        // see table below (1)
     byte compressionType;  // see table below (2)
     short colourCount;     // = the number of unique colours in the frame
     signed short X;        // = X position of this frame
     signed short Y;        // = Y position of this frame
     short frameWidth;      // = width of this frame
     short frameHeight;     // = height of this frame
     int dataOffset;        // = offset into the frame data (3)
     int compressedSize;    // = length of the compressed frame data
     int uncompressedSize;  // = length of the uncompressed frame data
     int colourTableOffset; // = position of the palette for this frame in the ColourTable
     int padding;           // = 0
}

1. Frame Type

Each frame has a type:

Type Description
0 This frame is a repeat of a previous frame
1 Flip Horizontally
2 Flip Vertically
3 Flip Horizontally and Vertically
4 This is a normal frame.
5 The frame is empty. i.e. there is no frame or palette data associated with this frame. Width and Height are 0.

2. Frame Compression

Frames can be compressed. Unit sprite files seem to use no compression at all, animations for encounters between battles (filename beginning M_) can be compressed using two methods (or be uncompressed).

Compression Type Decription
0 Uncompressed - the frame data consists of 1 byte indices in to the associated palette
1 Packbits - the frame is compressed using the PACKBITS compression scheme.
2 Zero Runs - the frame is compressed using the scheme detailed below

Zero Runs Compression

The algorithm for this method is as follows:

  1. Read a signed byte (we'll call this 'op')
  2. If the byte is < 0 then write -op 0s to output
  3. Otherwise, write op+1 literal bytes to output
  4. Go to step 1

3. Offset Into the Frame Data

This offset is into the frame data. i.e. this frame's data is at SpriteHeader.frameDataOffset + FrameHeader.dataOffset and goes on to SpriteHeader.frameDataOffset + FrameHeader.dataOffset + FrameHeader.compressedSize

Colour Table

Each colour is stored as follows:

struct Colour
{
     byte blue;
     byte green;
     byte red;
     byte padding; // =0 not used
}

The number of colours in the table is stored in the file header, and palettes are made up of entries from this data

Frame Data

This part of the file consists of all of the (potentially compressed) colour indexed data for each frame. To separate it, you must know the start in the buffer and size of each frame as listed in the frame headers.

Important Notes

Unit sprites have a few specific properties.

  • They are uncompressed
  • They only use 16 colours per palette.
  • Colours with each component < 8 will be transparent in-game; to use black in a sprite it is necessary to use RGB=(8,8,8).
  • Cyan, RGB=(0,255,255) is used to represent the unit shadow.
  • The frames are arranged with a stride of eight, for different directions follow on from the previous direction. e.g. the frames might be WALKING1_NORTHEAST, WALKING1_EAST, ... , WALKING1_NORTH, WALKING2_NORTHEAST, WALKING2_EAST ... WALKING2_NORTH etc. Note: some artillery units are the exception, since they have 16 directions; they have a corresponding stride of 16.
  • The game likely maps actions to frames using a Unit Type listed in the ARM file. All 'monsters' for example seem to have the same mapping.
Personal tools
communication