Closed zoalasaurusrawr closed 1 year ago
Hi the data on these is just raw texture data You can use a tool like raw texture cooker to get it One of the unknowns is probably the indicator for the format of the texture (ie. BC1, BC7 etc etc)
Thank you for the tip, let me try that!
EDIT: THAT DID THE TRICK EEEEEEEEEEEEEEE. I will update the format docs and try to upload the tool I made to decode them today!
Thank you for the tip, let me try that!
EDIT: THAT DID THE TRICK EEEEEEEEEEEEEEE. I will update the format docs and try to upload the tool I made to decode them today!
Btw i also suspect the value at 0E is mipcount, if the files get progressively smaller, it would probably indicate mipmaps
Thank you for the tip, let me try that! EDIT: THAT DID THE TRICK EEEEEEEEEEEEEEE. I will update the format docs and try to upload the tool I made to decode them today!
Btw i also suspect the value at 0E is mipcount, if the files get progressively smaller, it would probably indicate mipmaps
struct mipfileinfo {
u32 size;
u32 unk1; //always 6...
};
struct mipinfo {
u16 textureindex;
u8 mipindex;
u8 unk1; //slice index?
};
struct txtgheader {
char magic[8];
u16 width;
u16 height;
u16 texturecount;
u8 mipcount;
char unkblock[65];
mipinfo mipinfos[mipcount*texturecount];
mipfileinfo mipfileinfos[mipcount*texturecount];
};
txtgheader header @0x00;
//zstd data
heres what ive figured out for the format. the unknown block i have no clue on the details of
Some info on the unknown area.
Channels use the swap list at 0x18 to determine RGBA. 0x14 looks like another channel list, but it may be another value depending on 0x13 value and I don't know when that one is used.
The formats seem to be at 0x3C, with format and type as bytes. I assume the second one is type as it stays the same as format, but changes when srgb is used.
Also format 1 = ASTC_4x4_SRGB, 0 = ASTC_4x4_UNORM. Used by link.
Edit: The format might actually be a ushort, since there is also ASTC_8x8 0x105
Fantastic stuff @KillzXGaming! I have a utility to split these and I’d love to share any code if it would be helpful. I discovered for certain that each file contains multiple sizes of the same texture today. I was able to use texture cooker to convert the raw data to DDS, using Switch Swizzle and DXT1 for txtg files ending _Alb in the Totk rom.
Some info on the unknown area.
Channels use the swap list at 0x18 to determine RGBA. 0x14 looks like another channel list, but it may be another value depending on 0x13 value and I don't know when that one is used.
The formats seem to be at 0x3C, with format and type as bytes. I assume the second one is type as it stays the same as format, but changes when srgb is used.
Could you elaborate on this? I'm not really sure what the channels variable is for or where the format or channel type enums should be used. Your message talks about for format information being at 0x3C
, but even when I copy down your struct exactly, the offset of the format
field is 0x40
(via offsetof(textogo_header, format);
).
typedef struct {
uint16_t header_size;
uint16_t version;
uint32_t magic;
uint16_t width;
uint16_t height;
uint16_t texture_count;
uint8_t mip_count;
uint8_t unk1;
uint8_t unk2;
uint16_t padding;
uint8_t unk3;
uint32_t unk4;
uint8_t channels[4];
uint8_t checksum[32];
uint8_t format;
uint8_t type;
}textogo_header;
Fantastic stuff @KillzXGaming! I have a utility to split these and I’d love to share any code if it would be helpful. I discovered for certain that each file contains multiple sizes of the same texture today. I was able to use texture cooker to convert the raw data to DDS, using Switch Swizzle and DXT1 for txtg files ending _Alb in the Totk rom.
Do you think you could upload the tool you made? Thanks in advance.
I think this hex pattern sums up all the information we know so far. GitHub didn't like the .hexpat
extension so I made it .txt
. Is there anything I'm missing?
textogo.hexpat.txt
Some info on the unknown area. Channels use the swap list at 0x18 to determine RGBA. 0x14 looks like another channel list, but it may be another value depending on 0x13 value and I don't know when that one is used. The formats seem to be at 0x3C, with format and type as bytes. I assume the second one is type as it stays the same as format, but changes when srgb is used.
Could you elaborate on this? I'm not really sure what the channels variable is for or where the format or channel type enums should be used. Your message talks about for format information being at
0x3C
, but even when I copy down your struct exactly, the offset of theformat
field is0x40
(viaoffsetof(textogo_header, format);
).typedef struct { uint16_t header_size; uint16_t version; uint32_t magic; uint16_t width; uint16_t height; uint16_t texture_count; uint8_t mip_count; uint8_t unk1; uint8_t unk2; uint16_t padding; uint8_t unk3; uint32_t unk4; uint8_t channels[4]; uint8_t checksum[32]; uint8_t format; uint8_t type; }textogo_header;
This seems to be some struct padding problem. I changed my struct a little and it seems to be working now.
typedef struct {
uint16_t header_size;
uint16_t version;
uint32_t magic;
uint16_t width;
uint16_t height;
uint16_t texture_count;
uint8_t mip_count;
uint64_t unknown;
uint8_t channels[4];
uint8_t checksum[32];
uint8_t format;
uint8_t type;
}textogo_header;
Also format 1 = ASTC_4x4_SRGB, 0 = ASTC_4x4_UNORM. Used by link.
Edit: The format might actually be a ushort, since there is also ASTC_8x8
0x105
I ran my code on every textogo file in the game, and there are 4 other format values that are used but unaccounted for: 0x9
, 0xA
, 0xB
, and 0xC
. Interestingly, it seems like 0x8
isn't used at all. I figure the 4 unknown values are for BC6
and BC7
compression.
Also, how are you figuring out which value is which format?
I am implimented support for the format so I can tell what format is used.
Also I can confirm the checksum value is not quite a checksum, I assume it is just a unique hash used for every texture. Replacing the image works fine as is and the value always changes, even if the data is identical with another texture.
Currently known so far. Some small changes with the format, since I think it does use both values or something
I am implimented support for the format so I can tell what format is used.
Also I can confirm the checksum value is not quite a checksum, I assume it is just a unique hash used for every texture. Replacing the image works fine as is and the value always changes, even if the data is identical with another texture.
Awesome! I'm glad that you and others are more familiar with this territory. I feel like I have a long way to go towards really being decent at this type of work. I was able to work out the swizzle for DXT1 from the raw data, last night in code, but at this point I'm not familiar not familiar enough with the file formats to know if it's even useful to tackle the swizzle that way, or if it's going to be a thing where it's slightly different for each format.
In case it's useful, it looks like the Swizzle is just BGRA, at least in cases where I was able to use texture cooker to decode a DXT1 file.
public static byte[] ReadColor(this BinaryReader reader)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
var color = reader.ReadInt32();
var originalColor = Color.FromArgb(color);
return new byte[] { originalColor.B, originalColor.G, originalColor.R, originalColor.A };
}
When I get home a bit, I'll upload the code I'm using to split the individual files out from the original stream + zlib decompression. It feels like the total efforts in the thread are eclipsing anything I might be able to add. I'll make sure to update the gist as well, so that I don't mislead others on the file format as well!
Currently known so far. Some small changes with the format, since I think it does use both values or something
The area around the MipMap count seems weird to me. Mainly the positioning of the u16
padding after the two unknown byte values. I feel like they would put the FormatFlag
directly after Unk2
and then two bytes padding afterwards.
But even that seems weird to me, cause the header isn't padded to 4-byte regions, making the padding there somewhat redundant (if I understand how padding works correctly)
It might not be, though I think it's always 0. I'll need to make a dump of all the values used to understand some things more clearly.
Also something else I noticed, TextureSetting1 is a float value which is typically !f32 70
, but it's !f32 50
in MaterialsAlb. Changing it works (the game loads), but I can't see any visible changes. (Changed it to 10k, 100k, and -10)
It has been added.
I hope this is okay @KillzXGaming, I’ve spent quite a bit of time the last several days reverse engineering the txtg file format and I wrote up a gist in hopes that it will help others. The long and ushort of it is that it appears to be a modified version of the 6pack archive format, but with heavy modifications to use zstd instead of fastlz for single file entry compression.
https://gist.github.com/zoeysaurusrex/0c8a1ae2e218d1c76959765bf9e9c408