This thread is an attempt to collect information about the new texture format used on the Nintendo Switch, BNTX (Binary Texture). It's different from formats used on previous nintendo consoles (like the WiiU and the 3DS, at least afaik).
I started to write a tool to extract textures from the bntx container. Currently, it only supports DXT1 and DXT5 since this seems to be the most used format, due to the benefits of the compression. (image is 4 or 8x smaller than a raw rgba encoded image).
BNTX texture tool: https://github.com/gdkchan/BnTxx
I also made a tool to extract the Swich RomFS. Discussion about said container is out of the scope of this thread, but if anyone is interested, tool can be found here: https://gist.github.com/gdkchan/635187f5...53493f275f.
Overview of the format:
BNTX is basically a texture container. It can contain multiple textures, have a PATRICIA-trie based dictionary that allows quick access to textures using names as key, and also a relocation table that allows the binary to be loaded anywhere in memory and the addresses can be easily converted from relative offsets to absolute pointers.
Sections:
- BNTX Main header, contains pointers to the other sections, and also some lengths
- _STR String table section. First name is always an empty string "\0", used by the root node of the tree.
- _DIC Dictionary using the PATRICIA tree, each node have 16 bytes.
- BRTI Texture information. Contains one for each texture on the file.
- BRTD Texture data. BNTX contains only one of this section with all textures inside. Textures are aligned into 0x800 bytes blocks, and the 16 bytes header comes before the data.
- _RLT Relocation table, it's the last section on the file and contains the addresses for all pointers inside the file.
All the sections that starts with _ can be ignored if one just whiches to extract textures, because all data can be obtained from other sections too. The BRTD header can also be ignored because the only information it contains is the length of the data section (which is only useful if you're going to read it into memory and use the buffer directly).
Swizzling:
Switch textures uses swizzling, the DXT compressed textures have swizzling applied to the address of the 4x4 tiles. On the tile address, the bits from the X and Y coordinates are distributed using this pattern: yyyy x yy x y. However, after certain point it seems to use linear addressing, and this point is when either the numbers of available bits are over, or when the address grows bigger than 9 bits (?). Take this information with a grain of salt, since it's not guaranteed (and most likely isn't) accurate.
Anyway, here is a real example (from a 512x512 dxt5 texture) that maybe can help you better understand the address format:
x x x x x y y y y x y y x y 0 0 0 0
Note that the entire address have 18 bits, which is the size of 512 * 512 - 1 = 0x3ffff. Since we're talking about dxt5 textures here, the lower 4 bits are the address inside the 16 bytes tile data block, this one is linear and you don't need to worry about it.
You can find a most likely shite implementation of the above swizzle here:
https://github.com/gdkchan/BnTxx/blob/ma...Txx/BCn.cs
Some textures:
Those are some textures extracted from Puyo puyo tetris, the game I'm using to do this research, and also one of the few games that interests me on the Switch currently:
Any suggestion for improvement, correction or new information is welcomed.
TODO list:
- Figure out how non-compressed textures are swizzled (they seems to be encoded into 8x8 tile blocks but i'm not sure yet).
I started to write a tool to extract textures from the bntx container. Currently, it only supports DXT1 and DXT5 since this seems to be the most used format, due to the benefits of the compression. (image is 4 or 8x smaller than a raw rgba encoded image).
BNTX texture tool: https://github.com/gdkchan/BnTxx
I also made a tool to extract the Swich RomFS. Discussion about said container is out of the scope of this thread, but if anyone is interested, tool can be found here: https://gist.github.com/gdkchan/635187f5...53493f275f.
Overview of the format:
BNTX is basically a texture container. It can contain multiple textures, have a PATRICIA-trie based dictionary that allows quick access to textures using names as key, and also a relocation table that allows the binary to be loaded anywhere in memory and the addresses can be easily converted from relative offsets to absolute pointers.
Sections:
- BNTX Main header, contains pointers to the other sections, and also some lengths
- _STR String table section. First name is always an empty string "\0", used by the root node of the tree.
- _DIC Dictionary using the PATRICIA tree, each node have 16 bytes.
- BRTI Texture information. Contains one for each texture on the file.
- BRTD Texture data. BNTX contains only one of this section with all textures inside. Textures are aligned into 0x800 bytes blocks, and the 16 bytes header comes before the data.
- _RLT Relocation table, it's the last section on the file and contains the addresses for all pointers inside the file.
All the sections that starts with _ can be ignored if one just whiches to extract textures, because all data can be obtained from other sections too. The BRTD header can also be ignored because the only information it contains is the length of the data section (which is only useful if you're going to read it into memory and use the buffer directly).
Swizzling:
Switch textures uses swizzling, the DXT compressed textures have swizzling applied to the address of the 4x4 tiles. On the tile address, the bits from the X and Y coordinates are distributed using this pattern: yyyy x yy x y. However, after certain point it seems to use linear addressing, and this point is when either the numbers of available bits are over, or when the address grows bigger than 9 bits (?). Take this information with a grain of salt, since it's not guaranteed (and most likely isn't) accurate.
Anyway, here is a real example (from a 512x512 dxt5 texture) that maybe can help you better understand the address format:
x x x x x y y y y x y y x y 0 0 0 0
Note that the entire address have 18 bits, which is the size of 512 * 512 - 1 = 0x3ffff. Since we're talking about dxt5 textures here, the lower 4 bits are the address inside the 16 bytes tile data block, this one is linear and you don't need to worry about it.
You can find a most likely shite implementation of the above swizzle here:
https://github.com/gdkchan/BnTxx/blob/ma...Txx/BCn.cs
Some textures:
Those are some textures extracted from Puyo puyo tetris, the game I'm using to do this research, and also one of the few games that interests me on the Switch currently:
Any suggestion for improvement, correction or new information is welcomed.
TODO list:
- Figure out how non-compressed textures are swizzled (they seems to be encoded into 8x8 tile blocks but i'm not sure yet).