TX2

From MultimediaWiki
Jump to: navigation, search

Uses

This format is used in Disgaea: Hour of Darkness and other games by Nippon Ichi Software.

Format

The file consists of:

  1. a file header
  2. one or more color palettes as indicated in the header
  3. image data

The file may have garbage data after the end of the image. This should be discarded.

Header

Multibyte values in this format are stored with little-endian byte ordering.

typedef struct {
  uint16_t width;
  uint16_t height;
  uint16_t colors;   /* only values 16 and 256 have been observed */
  uint16_t unknown;
  uint16_t colors2;  /* purpose unknown, but always seems to be the same as colors */
  uint16_t palettes; /* number of palettes.  only 1 and 16 observed thus far */
  uint32_t padding;  /* always zero */
} HEADER;

Palette

The palettes follow immediately after the header, and all have the number of entries indicated by the color field in the file header. The palettes have no header of their own, and instead simply consist of each color:

uint32_t color;      /* 0xAABBGGRR in little endian */

In many images with no apparent need for transparency, the alpha value is always 0x80. Images which truly make use of the alpha channel have been observed, but not explored in detail yet.

Image Data

For 256 color images, each byte is a palette index, with bits 4 and 5 swapped. For the purposes of implementing a parser for this format, it is probably more efficient to reorder the palette while reading it, rather than swapping bits for each pixel.

For 16 color images, each byte gives two palette indexes - the first in the low nibble, the second in the high nibble.

Unswizzle

Sometimes the image data is swizzled (changed order in order to allow faster loading). To unswizzle, the following code can be used. pos is the position of the byte, counted from the start of the image data, x and y are the "real" coordinates. Width and height are the width and height of the whole image.

const int pos_list1[] = {
               0, 4, 8, 12, 1, 5, 9, 13,
               2, 6, 10, 14, 3, 7, 11, 15,
               4, 0, 12, 8, 5, 1, 13, 9,
               6, 2, 14, 10, 7, 3, 15, 11
};
      
int pos_list2[] = {
               4, 0, 12, 8, 5, 1, 13, 9,
               6, 2, 14, 10, 7, 3, 15, 11,
               0, 4, 8, 12, 1, 5, 9, 13,
               2, 6, 10, 14, 3, 7, 11, 15
};

void calcXY (int pos, int width, int height){

   int block = pos / 32;
   int line = block / (width/16);
  
   //The x and y coordinate of the upper left corner of a "block"
   int x_off = (block % (width/16)) * 16;
   int y_off = (line/2) * 4 + (line%2);
      
   int y = y_off + ((pos % 2)*2); //the line changes up and down on every bit
   int x = x_off;
  
   if (((y/4)%2)==0)
       x+= pos_list1[pos%32];
   else
       x+= pos_list2[pos%32];
      
   printf ("x:    %d   y: %d", x, y);
}