I've spent a lot of time on this and I have made a lot of progress, but there is several problems to solve still.

I have this old PS2 game and, as any curious person would, I put the disc in my computer and opened up data files in my hex editor.

After a lot of digging around I found a texture file format embedded in larger container files. I extracted these textures using a hacked together python script, and managed to reverse engineer a lot of the file. NOTE: It is in little endian. I then proceeded to write c++ code that parses these files and then uses imagemagick to convert them to jpg or png.

The images themselves use indexed colour, that is it has a palette of colours and uses an index to refer to them. The size of the palette in all images i've found so far is always 1024 bytes (256 colours) and is appended to the end of the image data.

One of the tricky parts of this for me is that the alpha values are confusing. They seem to be between 0 and 0x80 (128 in decimal) but I don't know how to deal with them. If I overwrite all alpha values to 0xFF the image comes out fine with no 'real' alpha channel, but I need to eventually be able to parse it so I can get the exact original images back. Leaving the alpha values as is makes the conversion fail technically, the image looks undesirable. Here is an example of what i mean: https://i.stack.imgur.com/R8lds.jpg

Here are the current structures that I've managed to reverse engineer and code into my parser so far

struct Header
    char header[4];
    unsigned long imageOffset;
    unsigned long paletteOffset;
    unsigned long fileSize;
    unsigned short width, height;
    char unknowndata[10];
    unsigned short id;

union colourU{
    unsigned long hex;
    unsigned char rgba[sizeof(long)];

struct Palette
    colourU colour[256];

I recently made some headway in reversing the unknown data in the header, but it's not much. Here is a sample of a header

4B 32 54 78 20 00 00 00 20 00 01 00 20 04 01 00 00 01 00 01 00 00 00 00 05 00 05 00 00 00 02 00

The first four bytes 4B 32 54 78 is a magic string 'K2Tx'

Then there is the imageOffset 20 00 00 00 and paletteOffset 20 00 01 00

The fileSize 20 04 01 00

Then there is 00 01 and 00 01 which is width and height of the image (256x256)

The unknown bytes section is 0xA bytes long which is divisible by 2, but not 4. which says to me that its either shorts or something else. I am unsure how to really understand these bytes without getting into the game code.

I am hoping someone might be able to help me by pointing me in the right direction.

All of this work was done just by observing many different sample files, I really didn't want to get out a disassembler and look at the code, although I may have to at some point. (Its MIPS III)

If you need a full file sample let me know

--- UPDATE ---

I've decided to name the game - it's Tenchu: Fatal Shadows

After messing around with emulator and cheat engine, managed to uncover some things.

The first two bytes of the unknown data is actually some sort of pixel x rotation, and then the next two are the y rotation. When i changed them, the texture pixels would change pixel positions on the screen (rotated within their bounds).

This might not be that important as they are usually set to zero.

The next two bytes and two bytes after that are both shorts, but I am not sure exactly what they do. When I change them the whole texture goes strange and it corrupts some of the memory within the game itself, perhaps some sort of or offset or array index.

Seeing as these may only has use within the game's memory context, I will ignore these for now

The last two bytes of the originally unknown chunk are simply some sort of interleave flag (a guess) which is TRUE if it is set as 0x02 or in binary b10 Which is interesting, because i have found a few textures which are in that format. Usually those are the ones used on 3d models ingame. Here is 2 jpg examples of these https://i.stack.imgur.com/SPzgn.jpg Perhaps some sort of pixel interleaving?

There is a link to a sample in the comments

  • Hi - nice job so far. For the alpha, can you guess what some of the values should be by observing them in game? I'd guess your 0-80 maps onto 0-ff with a linear relationship - you've tried just doubling them all I'd guess? So if you can work out that a value 0x40 you have should be 0x90 say, and you can get a few more examples you can try graphing them and working out what the pattern is. Or of course it could just be a lookup table in the code somewhere that makes no sense as a graph. How does the PS2 graphics hardware accept alpha values?
    – Rup
    Jun 17, 2017 at 9:42
  • For the other ten bytes - does it matter? If this is a page of sprites it might be some property of that - centre pixel of each sprite, count in each dimension? (although doesn't look right from your example at first glance) Can you find more examples with the same or different unknown ten bytes? If different, does your code so far unpack those files fine - it's not format, or palette format or similar?
    – Rup
    Jun 17, 2017 at 9:44
  • Finally, can you modify these files and feed them back into the game? e.g. change all the alpha values by +0x10 and see what happens, change the first short in the unknown bytes and see if the pallete goes wrong, etc. I don't remember how easy it is to do that for PS2, but I've seen someone edit PS1 games before and play them on a modified console. Do you have a working emulator?
    – Rup
    Jun 17, 2017 at 9:53
  • Can you provide a sample file? (or just name the game)
    – TkTech
    Jun 18, 2017 at 16:02
  • I don't have a sample on me at the moment because I am away from my laptop, but the game is Tenchu: Fatal Shadows
    – Samson
    Jun 20, 2017 at 22:49


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.