Original Post
Hi there. I've been analyzing proprietary file formats for a while now, in an attempt to make a (somewhat) universal converter. I'm now analyzing the Unreal static mesh format (specifically, the old one for UE2), the raw version of which is, according to Google, completely undocumented, and have noticed something quite strange. The mesh is broken into sections for vertices, vertex colors, faces, edges, mapping coordinates, etc., and at the top of each section is a count of the number of elements the section contains. The count is what I'm having trouble with.
It isn't a regular signed or unsigned 16-bit value but a combination of up to two bytes whose individual values have no direct correlation with the count. The actual count is derived using some bit math I can't figure out. Here are some examples, from the Aidabear (raw) mesh file:
Vertex Section
Count is given as two bytes: 0x7F (127) and 0x07 (7), in that order, so together they would be 0x077F (1919) or 0x7F07 (32519). The actual vertex count is 511. In binary, you get this:
0x7F = 0111 1111
0x07 = 0000 0111
511 = 0000 0001 1111 1111
We'll come back to this in a minute.
Face Section
Count is given as 0x44 (68) and 0x20 (32), in that order, so together they are 0x2044 (8620) or 0x4420 (17440). The actual index count is 684. In binary, you get this:
0x44 = 0100 0100
0x20 = 0010 0000
684 = 0000 0010 1010 1100
I can't tell how these values correlate. We'll come back to it.
Edge Section
This is the one that I thought made sense until I studied the other two sections. Count is given as 0x6C (108) and 0x24 (36), so together they are 0x246C (9324) or 0x6C24 (27684). The actual index count is 1174. In binary, you get this:
0x6C = 0110 1100
0x24 = 0010 0100
1174 = 0000 0100 1001 0110
Now, let's assume for the moment that the 7th bit (at position 6) in the first byte (0x6C) is a marker that tells the mesh loader to use a second byte (in this case, 0x24), which is stacked onto the end (i.e., shifted six bits and AND'ed together). This gives us 0000 1001 0010 1100, which is one bit out of place, so let's also mask out the first bit (position 0). That gives us the correct value.
In short: (0x24 << 6) & ((0x6C & MASK) >> 1) = 0x0496 (the actual count), where MASK = 0011 1111.
That's an awful lot of math for something that fits easily into two bytes.
Problem: this does not work with the other two sections. You can do the math real quick, but really you just have to look at the binary values posted here and see right away that they don't match. In the Vertex section, you get the correct value (511) by leaving the 1st bit in 0x7F alone . . . but what in this particular case dictates that it must remain untouched? So, I'm turning to wiser programmers like you to help me figure this one out.
If it helps, here's another example from Arachnid_Gib_s03:
Vertex Section
Count is given as 0x0E (14), which is the actual number of vertices. There is only one byte. (This is also the case in the Face and Edge sections, which contain 12 and 32 elements, respectively, described using exactly one byte.) Something in this value (0x0E) is missing that would otherwise tell the mesh loader to look for a second byte. It seems most likely the 7th bit (since two of the three values in AidaBear have zero as their first bit). Since I've only looked at two models so far (the two mentioned here), I can't tell for sure. If I find a model with exactly 127 vertices, it might help, but I'm skeptical that one even exists, and I'm not about to serialize every one of the 2,452 models by hand!
So. . .
With this information, how do you get 0x02AC (684) from combining 0x44 and 0x20? How do you get 0x01FF (511) from combining 0x7F and 0x07? What do the extraneous bits represent? I thank you in advance for your help. Hopefully I'll get this figured out soon, but any timely assistance you can offer is greatly appreciated.
It is quite possible that the mesh file contains other data that dictates the size of the count field in each section. If no one can help me with the bit math, I'll start looking elsewhere. The file format is incredibly obscure, and, as far as I can tell, documentation is nonexistent.
[Edited by - Tom on September 22, 2010 1:43:39 PM]
It isn't a regular signed or unsigned 16-bit value but a combination of up to two bytes whose individual values have no direct correlation with the count. The actual count is derived using some bit math I can't figure out. Here are some examples, from the Aidabear (raw) mesh file:
Vertex Section
Count is given as two bytes: 0x7F (127) and 0x07 (7), in that order, so together they would be 0x077F (1919) or 0x7F07 (32519). The actual vertex count is 511. In binary, you get this:
0x7F = 0111 1111
0x07 = 0000 0111
511 = 0000 0001 1111 1111
We'll come back to this in a minute.
Face Section
Count is given as 0x44 (68) and 0x20 (32), in that order, so together they are 0x2044 (8620) or 0x4420 (17440). The actual index count is 684. In binary, you get this:
0x44 = 0100 0100
0x20 = 0010 0000
684 = 0000 0010 1010 1100
I can't tell how these values correlate. We'll come back to it.
Edge Section
This is the one that I thought made sense until I studied the other two sections. Count is given as 0x6C (108) and 0x24 (36), so together they are 0x246C (9324) or 0x6C24 (27684). The actual index count is 1174. In binary, you get this:
0x6C = 0110 1100
0x24 = 0010 0100
1174 = 0000 0100 1001 0110
Now, let's assume for the moment that the 7th bit (at position 6) in the first byte (0x6C) is a marker that tells the mesh loader to use a second byte (in this case, 0x24), which is stacked onto the end (i.e., shifted six bits and AND'ed together). This gives us 0000 1001 0010 1100, which is one bit out of place, so let's also mask out the first bit (position 0). That gives us the correct value.
In short: (0x24 << 6) & ((0x6C & MASK) >> 1) = 0x0496 (the actual count), where MASK = 0011 1111.
That's an awful lot of math for something that fits easily into two bytes.
Problem: this does not work with the other two sections. You can do the math real quick, but really you just have to look at the binary values posted here and see right away that they don't match. In the Vertex section, you get the correct value (511) by leaving the 1st bit in 0x7F alone . . . but what in this particular case dictates that it must remain untouched? So, I'm turning to wiser programmers like you to help me figure this one out.
If it helps, here's another example from Arachnid_Gib_s03:
Vertex Section
Count is given as 0x0E (14), which is the actual number of vertices. There is only one byte. (This is also the case in the Face and Edge sections, which contain 12 and 32 elements, respectively, described using exactly one byte.) Something in this value (0x0E) is missing that would otherwise tell the mesh loader to look for a second byte. It seems most likely the 7th bit (since two of the three values in AidaBear have zero as their first bit). Since I've only looked at two models so far (the two mentioned here), I can't tell for sure. If I find a model with exactly 127 vertices, it might help, but I'm skeptical that one even exists, and I'm not about to serialize every one of the 2,452 models by hand!
So. . .
With this information, how do you get 0x02AC (684) from combining 0x44 and 0x20? How do you get 0x01FF (511) from combining 0x7F and 0x07? What do the extraneous bits represent? I thank you in advance for your help. Hopefully I'll get this figured out soon, but any timely assistance you can offer is greatly appreciated.
It is quite possible that the mesh file contains other data that dictates the size of the count field in each section. If no one can help me with the bit math, I'll start looking elsewhere. The file format is incredibly obscure, and, as far as I can tell, documentation is nonexistent.
[Edited by - Tom on September 22, 2010 1:43:39 PM]