Jump to content

Recommended Posts

Posted

Good day,

I'm having some trouble with the Fable 2 .tex files. 

An old post on the Zenhax forums shows that they are apparently LZMA:192k compressed. I've tried reconfiguring the Tex converter for Fable 3 using texconv to rewrite them as .dds; as well as some tools for finding the texture. 
 

Notably, the headers are stripped from the file and placed elsewhere. I can rebuild the file with the headers to share if needed, but I've just attached some of the .tex's with their corresponding headers. 

New WinRAR archive.rar

Posted

After dicking about a little, I think the texture is starting to show itself? 

Not 100% sure, but someone more experienced with texture formats chiming in would be a great help 🙂

image.png

Posted

I guess the data is compressed, as you already mentioned, so you won't get much from looking at the raw data, unless it happens to use one of those compression types in ImageHeat.  Each file contains several images, probably mipmaps, and each image has a header of 0x30 bytes with the data size and other info.  At 0x30 bytes in each image (mostly) is the width/height as 2 Short values.  The amount of data in the files is far too small for it to be raw image data.  Although you mention LZMA, I can't find a suitable offset to decompress the data in any recognisable way.

 

  • Like 1
Posted
4 minutes ago, DKDave said:

I guess the data is compressed, as you already mentioned, so you won't get much from looking at the raw data, unless it happens to use one of those compression types in ImageHeat.  Each file contains several images, probably mipmaps, and each image has a header of 0x30 bytes with the data size and other info.  At 0x30 bytes in each image (mostly) is the width/height as 2 Short values.  The amount of data in the files is far too small for it to be raw image data.  Although you mention LZMA, I can't find a suitable offset to decompress the data in any recognisable way.

 

I ended up taking an autistic route of just writing a script which outputs an atlas to get as much visual data as I can

image.png

  • Engineers
Posted (edited)

You sure it's LZMA? I noticed that mip map with comp flag 11 are compressed. Mip map with comp flag 7 are uncompressed.

image.thumb.png.d1acb382598be2b2d6d7772be36dcb28.png

Also about compressed files. I think they are chunked bcs i see some data which it doesn't look compressed. Size is 448 bytes.

Edited by h3x3r
  • Like 2
Posted
1 hour ago, h3x3r said:

You sure it's LZMA? I noticed that mip map with comp flag 11 are compressed. Mip map with comp flag 7 are uncompressed.

image.thumb.png.d1acb382598be2b2d6d7772be36dcb28.png

Also about compressed files. I think they are chunked bcs i see some data which it doesn't look compressed. Size is 448 bytes.

not 100%, i say that only because when i intially researched the format that's what i found on the xentax forums. 

https://web.archive.org/web/20210724182746/https://forum.xentax.com/viewtopic.php?t=4571#p39375

I don't know anything about 2d file formats but after trying to parse dimensions in big endian, immediately after each 0x30 header, it comes out as
 

Entry 0: type=0x1 off=0x0 size=6100, dims=256x128
Entry 1: type=0x1 off=0x1804 size=1896, dims=128x64
Entry 2: type=0x1 off=0x1f9c size=796, dims=64x32

entry 0 is interpreted from:

01 00 00 80 02 1A 01 4D 05 01 0B 02 04 38 00 0E

image.png

  • Engineers
Posted

Here's 010 Template... Not sure about compression. 7Zip can't open tex.

//------------------------------------------------
//--- 010 Editor v14.0 Binary Template
//
//      File: 
//   Authors: 
//   Version: 
//   Purpose: 
//  Category: 
// File Mask: 
//  ID Bytes: 
//   History: 
//------------------------------------------------
BigEndian();OutputPaneClear();
local uint32 i;

uint32 Sign;
uint32 RawDataSize;
uint32 Unknown_0;
uint32 Unknown_1; // maybe mipmap def size
uint32 TextureWidth;
uint32 TextureHeight;
uint32 PixelFormat;
uint32 MipMap;
uint32 MipMapOffset[MipMap];


for (i=0; i < MipMap; i++)
{
    FSeek(MipMapOffset[i]);
    struct
    {
        uint32 CompFlag;
        uint32 DataOffset;
        uint32 DataSize;
        uint32 Unknown_3;
        uint32 Unknown_4;
        uint32 Unknown_5;
        uint32 Unknown_6;
        uint32 Unknown_7;
        uint32 Unknown_8;
        uint32 Unknown_9;
        uint32 Unknown_10;
        uint32 Unknown_11;
        if (CompFlag == 7)
        {
            ubyte MipMapData[DataSize];
        }
        else
        {
            uint16 MipWidth;
            uint16 MipHeight;
            ubyte UnkData[440];
            ubyte MipMapData[DataSize-448];
        }
    }MipMapDef;
}

 

  • Like 1
  • Engineers
Posted

And what about "XMemDecompress" since it's xbox360 game? But i have no idea how to handle this.... You can get compressed size from DataSize - 448. But not sure about decompressed size. You can get it from "Image width * Image height" and divide it by pixel fomat. DXT1 = /4, DXT3/5 = /2. But that's just a wild guess.

Posted (edited)
7 hours ago, h3x3r said:

And what about "XMemDecompress" since it's xbox360 game? But i have no idea how to handle this.... You can get compressed size from DataSize - 448. But not sure about decompressed size. You can get it from "Image width * Image height" and divide it by pixel fomat. DXT1 = /4, DXT3/5 = /2. But that's just a wild guess.

for me that gives me always the same offset for every mip, is that normal?

MIP 2 COMP_FLAG: 11
MIP 2 DATA_OFFSET: 48
MIP 2 DATA_SIZE: 1360
MIP 2 UNK3: 0
MIP 2 UNK4: 0
MIP 2 UNK5: 0
MIP 2 UNK6: 0
MIP 2 UNK7: 0
MIP 2 UNK8: 0
MIP 2 UNK9: 0
MIP 2 UNK10: 0
MIP 2 UNK11: 0
MIP 3 COMP_FLAG: 11
MIP 3 DATA_OFFSET: 48
MIP 3 DATA_SIZE: 692
MIP 3 UNK3: 0
MIP 3 UNK4: 0
MIP 3 UNK5: 0
MIP 3 UNK6: 0
MIP 3 UNK7: 0
MIP 3 UNK8: 0
MIP 3 UNK9: 0
MIP 3 UNK10: 0
MIP 3 UNK11: 0
MIP 4 COMP_FLAG: 7
MIP 4 DATA_OFFSET: 48
MIP 4 DATA_SIZE: 512
MIP 4 UNK3: 0
MIP 4 UNK4: 0
MIP 4 UNK5: 0
MIP 4 UNK6: 0
MIP 4 UNK7: 0
MIP 4 UNK8: 0
MIP 4 UNK9: 0
MIP 4 UNK10: 0
MIP 4 UNK11: 0
MIP 5 COMP_FLAG: 7
MIP 5 DATA_OFFSET: 48
MIP 5 DATA_SIZE: 128
MIP 5 UNK3: 0
MIP 5 UNK4: 0
MIP 5 UNK5: 0
MIP 5 UNK6: 0
MIP 5 UNK7: 0
MIP 5 UNK8: 0
MIP 5 UNK9: 0
MIP 5 UNK10: 0
MIP 5 UNK11: 0

 

 
Edited by AexaDev
Posted (edited)
On 9/28/2025 at 4:22 PM, h3x3r said:

And what about "XMemDecompress" since it's xbox360 game? But i have no idea how to handle this.... You can get compressed size from DataSize - 448. But not sure about decompressed size. You can get it from "Image width * Image height" and divide it by pixel fomat. DXT1 = /4, DXT3/5 = /2. But that's just a wild guess.

as far as I can tell it uses a modified version of zlib/ deflate. based on what I can find in ida, they only use 1 method to decompress the data.

I asked in the discord that are trying to decomp the game, and they say that it should be the same decompression method used for the .bnk files which is lzx for everything.

there are 2 versions of bnk files which are handled slightly differently. I've uploaded my bnk reader here, which details both ver 2 and 3, but I have no idea if that will help. 

furthermore, some of the .tex files don't seem to want to play nice with your 010 script. might just be my own idiocy, though.

 

bnk_reader.py

Edited by vistekis
  • Engineers
Posted
3 hours ago, vistekis said:

tex files don't seem to want to play nice with your 010 script.

Did you put the header into texture buffer first? It was designed like that... Also XMemDecompress is LZX. Also there's no way it's zlib/deflate. Offzip can't output anything...

Posted
6 hours ago, h3x3r said:

Did you put the header into texture buffer first? It was designed like that... Also XMemDecompress is LZX. Also there's no way it's zlib/deflate. Offzip can't output anything...

yes of course. this is my own idiocy, I didn't realise, but some textures are cut in to 3 parts so it can't parse the whole thing. 

I get the error:

*ERROR Line 32: Template passed end of file at variable 'CompFlag'. ( see above sentence )

re: xmemdecompress

this isn't something I have any idea what I'm doing with, so I'll try to figure something out

New WinRAR archive.rar

  • Engineers
Posted

Here's bms I did for BNK files. Since I didn't found one.

get BaseFileName basename
endian big
comtype zlib_noerror

get BaseOffset uint32
get Unknown_0 uint32
get Unknown_1 ubyte

do
	get ZSize uint32
	get Size uint32
	math TotalZSize + ZSize
	math TotalSize + Size
	savepos Offset
	getdstring ZLibData ZSize
	append 0
	
	if ZSize != 0
		log MEMORY_FILE1 Offset ZSize
	endif
while ZSize != 0

clog MEMORY_FILE2 0 TotalZSize TotalSize -1

goto 0 -2
get ResourceCount uint32 -2

for i = 0 < ResourceCount
	get StrLen uint32 -2
	getdstring ResourceName StrLen -2
	get Offset uint32 -2
	get Size uint32 -2
	math Offset + BaseOffset -2
	string FileName p= "%s/%s" BaseFileName ResourceName
	log FileName Offset Size
next i

 

Posted
20 hours ago, vistekis said:

yes of course. this is my own idiocy, I didn't realise, but some textures are cut in to 3 parts so it can't parse the whole thing. 

I get the error:

*ERROR Line 32: Template passed end of file at variable 'CompFlag'. ( see above sentence )

re: xmemdecompress

this isn't something I have any idea what I'm doing with, so I'll try to figure something out

New WinRAR archive.rar 289.18 kB · 2 downloads

I was writing a Noesis addon it does seem to use xmem

Posted
1 hour ago, AexaDev said:

I was writing a Noesis addon it does seem to use xmem

Yes I think you’re both right..

have you made much progress? I think I found the process which calls the decomp, but I haven’t had a thorough look quite yet

Posted
2 hours ago, h3x3r said:

Here's bms I did for BNK files. Since I didn't found one.

get BaseFileName basename
endian big
comtype zlib_noerror

get BaseOffset uint32
get Unknown_0 uint32
get Unknown_1 ubyte

do
	get ZSize uint32
	get Size uint32
	math TotalZSize + ZSize
	math TotalSize + Size
	savepos Offset
	getdstring ZLibData ZSize
	append 0
	
	if ZSize != 0
		log MEMORY_FILE1 Offset ZSize
	endif
while ZSize != 0

clog MEMORY_FILE2 0 TotalZSize TotalSize -1

goto 0 -2
get ResourceCount uint32 -2

for i = 0 < ResourceCount
	get StrLen uint32 -2
	getdstring ResourceName StrLen -2
	get Offset uint32 -2
	get Size uint32 -2
	math Offset + BaseOffset -2
	string FileName p= "%s/%s" BaseFileName ResourceName
	log FileName Offset Size
next i

 

There are 2 versions of bnk files

The non-English speech.bnk files are V2 BNK files, for whatever reason, instead of the typical V3 BNK files which are in the game 

In V3 BNK files, the BNK-header points to the beginning of the file-data, with the file-table following immediately after the header.  
In V2 BNK files, the BNK-header points to the beginning of the file-table, with the the file-data beginning after the header, typically at an offset of 16-bytes relative to the BNK file.

In V3 BNK files, the file-table is terminated by a compressed-file-table-chunk with a compressed-size of 0.  
In V2 BNK files, the file-table is terminated implicitly by the end of the BNK file.

In V3 BNK files, the offset for a file entry's data, within the file-table, is relative to the beginning of the file-data as pointed to in the BNK-header.  
In V2 BNK files, the offset for a file entry's data, within the file-table, is relative to the beginning of the entire BNK file.

In V3 BNK files, the data of each file is aligned to an even boundary.
In V2 BNK files, the data of each file is unaligned.

 

Posted (edited)
5 hours ago, vistekis said:

Yes I think you’re both right..

have you made much progress? I think I found the process which calls the decomp, but I haven’t had a thorough look quite yet

pretty close to finish

Edited by AexaDev
Posted (edited)

There is a higher version of that one, but really the textures are truly awful in this game even for the time, essentially nothing above 256 pixels unless it's environmental, most is 128, and the weapons are by far the worst with the Red Dragon pistol for example having a 64x64 texture worse than pixel art, even in-game one can see it how incredibly blurry it is really just the vague suggestion of a gun. How did they get away with it? I guess I didn't care too much when I was a kid haha. Anyway this is just info from doing a casual rip a few weeks ago, it's a messy method and not very useful tbh but interesting. If it helps with comparison to check against here are the child hero textures
000001C92D9259A0.png.8605ed375e4c2280f92234bbf0b82f8d.png
000002398413ADD0.png.e7b02dd6aba7f5071f5a0ba59aee9cdc.png
000001C9405A6590.png.5bb9c6cc2b4f94f781ad5c820449f075.png

Edited by CharlieV
Posted
4 hours ago, CharlieV said:

There is a higher version of that one, but really the textures are truly awful in this game even for the time, essentially nothing above 256 pixels unless it's environmental, most is 128, and the weapons are by far the worst with the Red Dragon pistol for example having a 64x64 texture worse than pixel art, even in-game one can see it how incredibly blurry it is really just the vague suggestion of a gun. How did they get away with it? I guess I didn't care too much when I was a kid haha. Anyway this is just info from doing a casual rip a few weeks ago, it's a messy method and not very useful tbh but interesting. If it helps with comparison to check against here are the child hero textures
000001C92D9259A0.png.8605ed375e4c2280f92234bbf0b82f8d.png
000002398413ADD0.png.e7b02dd6aba7f5071f5a0ba59aee9cdc.png
000001C9405A6590.png.5bb9c6cc2b4f94f781ad5c820449f075.png

there are higher resolution textures, but they're compressed...

idk how to decompress them sadly, not something I know anything about. not that that's saying much

Posted

Ah I thought progress was being made on that, just providing a reference to check against. I'm not talking about mips myself those are there too in full grids, I only mention version because of course there are also lower res LOD textures as well, full>LOD>mip, just not for weapons because they're already lower than they ever should have been, it's crazy. Again, even the full uncompressed textures are awful for a lot of stuff and it can be seen in-game easily, so 'higher resolution' is a bit relative. 

Obviously ideally we'd be able to extract the textures directly, but the model plugin being worked on certainly won't be useless without that regardless of texture progress, ripping the textures is very viable, tedious yes, but simple enough for specific things rather than the entire game. I've gone through more hoops than that in the past! 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...