Skip to content

Instantly share code, notes, and snippets.

@sigsegv-mvm
Last active April 22, 2024 04:36
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save sigsegv-mvm/0f07b1c6d8dd56885f74e03758c11e58 to your computer and use it in GitHub Desktop.
Save sigsegv-mvm/0f07b1c6d8dd56885f74e03758c11e58 to your computer and use it in GitHub Desktop.
Reverse-engineered EXAPUNKS ".TEX" texture file format details
TEX FILE FORMAT
Reverse engineering by sigsegv, 20180914.
All values are little-endian.
0x00 int: TEX file version / magic number [1002 = 0x000003EA]
0x04 int: data resolution [x]
0x08 int: data resolution [y]
0x0C int: color format { 0 => invalid, 1 => 8BPP, 2 => RGBA }
0x10 int: display resolution [x]
0x14 int: display resolution [y]
0x18 int: display bounds [lower x]
0x1C int: display bounds [lower y]
0x20 int: display bounds [upper x]
0x24 int: display bounds [upper y]
0x28 float: crop offset [x]
0x2C float: crop offset [y]
0x30 float: sprite linking info [x]
0x34 float: sprite linking info [y]
0x38 int: number of LZ4-compressed data bytes
0x3C byte[]: LZ4-compressed data bytes...
NOTES:
- "data resolution" refers to the resolution of the data actually contained in the file
- "display resolution" refers to the nominal display resolution of the image in the game
- half-sized textures have the same display resolution and display bounds as their full-sized counterparts;
they simply have their data resolution numbers halved and contain a quarter as much image data
- "display bounds" represents a pair of min and max coordinates that the texture occupies;
typically the lower bound will be (0,0) and the upper bound will be (display_res_x,display_res_y)
- the "crop offset" data needs further investigation
- the "sprite linking info" is apparently used for player and opponent EXA sprites, to link together
different sprite parts based on a magenta mask (R=0xFF, G=0x00, B=0xFF, A=0xFF)
@L0891-3BDBFF
Copy link

is this format also suitable for mobius front '83?

@sigsegv-mvm
Copy link
Author

is this format also suitable for mobius front '83?

I'll take a look.

On an initial glance, the TEX file format version was bumped up by 2, from 1002 (0x3EA) to 1004 (0x3EC).

I'll take a look at the rest of the fields and see what changed, if anything.

@L0891-3BDBFF
Copy link

is this format also suitable for mobius front '83?

I'll take a look.

On an initial glance, the TEX file format version was bumped up by 2, from 1002 (0x3EA) to 1004 (0x3EC).

I'll take a look at the rest of the fields and see what changed, if anything.

oh, I wasn't expected that someone is still reverse engineering a small game that very few people plays :)
I‘ll examine the file head to see what's different from EXAPunks .tex

@sigsegv-mvm
Copy link
Author

Actually, it looks like @FiddyFive has already gone ahead and forked this gist to update it for TEX file version 1005, used in Zachtronics Solitaire Collection. https://gist.github.com/FiddyFive/ca6d110823f7dce31bc8d2884e9fdc0f

So for Mobius Front '83, we're looking at TEX file version 1004, which we'd expect to be somewhere in the middle.

@sigsegv-mvm
Copy link
Author

sigsegv-mvm commented Apr 22, 2024

I've already had a chance to take a cursory glance at the game code in dnSpy. (RIP dnSpy... it was sad that you died.)

I don't even remember which .NET deobfuscator I ran the MF83 executable file through back in Nov 2021. I just know that I still have the game installed, and so I still have the deobfuscated EXE file laying around from when I was fiddling around with it back then. (Doing fun things like flipping the bit for debug mode. 🙂)

Here's what I've thrown together.

It does have the multiple-images-per-file feature, as in version 1005. But it doesn't have the extra few fields that 1005 added near the end, just before the LZ4-compressed pixel data. EDIT: Actually, it does have the added int field; but not the two additional floats.

So it looks something like this:

File header:

0x00 int: TEX file version / magic number [1004 = 0x000003EC]
0x04 int: number of images in the file

The following structure is repeated, as many times as there are images in the file
 (as specified at offset 0x04 in the file header):

0x00 int:    data resolution [x]
0x04 int:    data resolution [y]
0x08 int:    color format { 0 => invalid, 1 => 8BPP, 2 => RGBA }
0x0C int:    display resolution [x]
0x10 int:    display resolution [y]
0x14 int:    display bounds [lower x]
0x18 int:    display bounds [lower y]
0x1C int:    display bounds [upper x]
0x20 int:    display bounds [upper y]
0x24 float:  crop offset [x]
0x28 float:  crop offset [y]
0x2C float:  unknown [x]
0x30 float:  unknown [y]
0x34 int:    something related to colorblind mode
0x38 int:    number of LZ4-compressed data bytes
0x3C byte[]: LZ4-compressed data bytes...

I don't know if the latter pair of floats is still actually "sprite linking info" or not. (I wouldn't have had the slightest idea what it'd ostensibly be, if not for having written down extra notes when I originally made this document back in 2018.) Sprite-linking seems like a fairly EXAPUNKS-specific feature. It's still a pair of floats, stored into a Vector2, though. Could be vestigial; could be repurposed for some other use in MF83. EDIT: Yeah it's something different.

@sigsegv-mvm
Copy link
Author

Okay so I actually managed to find my deobfuscated, annotated EXE of EXAPUNKS, still datestamped to Sep 2018! Which is pretty rad.

A couple things my prior post missed:

  • I failed to notice that an additional int field was added, just before the LZ4 length and data fields. Based on a quick look, it seems to be related to colorblind mode.
  • The pair of floats that were previously "sprite linking info" for EXAPUNKS are still there. At first I wasn't sure if that was just a vestigial leftover or if the fields are actually used for something else now. Well, they are used for something else by MF83. I think it's another set of bounds, that may be involved in things turning white or drawing boxes. Maybe I should fire up the game again with the debug bit flipped... because I think the level editor may have used white rectangles in some form? 🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment