vistekis Posted September 21 Posted September 21 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
vistekis Posted September 22 Author Posted September 22 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 🙂
DKDave Posted September 22 Posted September 22 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. 1
vistekis Posted September 22 Author Posted September 22 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
Engineers h3x3r Posted September 23 Engineers Posted September 23 (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. 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 September 23 by h3x3r 2
vistekis Posted September 23 Author Posted September 23 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. 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
Engineers h3x3r Posted September 23 Engineers Posted September 23 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; } 1
Engineers h3x3r Posted September 28 Engineers Posted September 28 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.
AexaDev Posted September 28 Posted September 28 (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 September 28 by AexaDev
Engineers h3x3r Posted September 29 Engineers Posted September 29 The absolute offsets are in header file. That 48 bytes offset is in texture buffer. So yes it's normal.
vistekis Posted September 30 Author Posted September 30 (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 September 30 by vistekis
vistekis Posted September 30 Author Posted September 30 https://github.com/mistydemeo/quickbms/blob/master/unz.c#L1035 xmemdecompress doesnt look like this at all. No xmem header. I didn’t have time to look thoroughly though
Engineers h3x3r Posted September 30 Engineers Posted September 30 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...
vistekis Posted Tuesday at 01:45 PM Author Posted Tuesday at 01:45 PM 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 h3x3r Posted Wednesday at 09:21 AM Engineers Posted Wednesday at 09:21 AM 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
AexaDev Posted Wednesday at 10:44 AM Posted Wednesday at 10:44 AM 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
vistekis Posted Wednesday at 11:49 AM Author Posted Wednesday at 11:49 AM 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
vistekis Posted Wednesday at 11:57 AM Author Posted Wednesday at 11:57 AM 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.
AexaDev Posted Wednesday at 04:32 PM Posted Wednesday at 04:32 PM (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 Wednesday at 04:55 PM by AexaDev
AexaDev Posted Wednesday at 05:22 PM Posted Wednesday at 05:22 PM 48 minutes ago, AexaDev said: pretty close to finish 1
vistekis Posted Wednesday at 10:58 PM Author Posted Wednesday at 10:58 PM Are these the compressed mips?
CharlieV Posted Saturday at 06:21 AM Posted Saturday at 06:21 AM (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 Edited Saturday at 06:23 AM by CharlieV
vistekis Posted Saturday at 10:38 AM Author Posted Saturday at 10:38 AM 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 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
Engineers h3x3r Posted Saturday at 11:59 AM Engineers Posted Saturday at 11:59 AM These are compresed btw. The problem is find valid offset for compressed data... I believe it's lzx.
CharlieV Posted yesterday at 12:22 AM Posted yesterday at 12:22 AM 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!
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now