Difference between revisions of "FF8/FileFormat X"
my_wiki>MaKiPL (Added Textures info + algorithms) |
my_wiki>MaKiPL (→UV calculation algorithm) |
||
Line 317: | Line 317: | ||
=== UV calculation algorithm === | === UV calculation algorithm === | ||
− | Float U = (float)U_Byte / (float)(TIM_Texture_Width * 2) + ((float)Texture_Page/(TIM_Texture_Width * 2)); | + | Float U = (float)U_Byte / (float)(TIM_Texture_Width * 2) + ((float)Texture_Page/(TIM_Texture_Width * 2)); |
=== Texture page calculation === | === Texture page calculation === |
Revision as of 11:26, 6 March 2015
By MaKiPL. Thanks for help in research for: shakotay2 (XeNTaX), Halfer, Yagami Light.
Contents
Info
.X file is uncompressed 3D stage model with texture embedeed. The file contains basic info (currently unknown, probably for editor?), camera data, movement, translations and geometry data.
Name | Usually starting with: | Description |
---|---|---|
Info/Script | E8 FF BD 27 01 00 02 | Currently unknown. Probably header + info, that is not needed in game itself. Can be null'ied and nothing will happen ingame. |
Camera data + movement | 02 00 08 00 20 00 (usually 0x5d4/8) | Camera animations, movement (pre-keyed) |
Geometry | 01 00 00 00 08 (See geometry section info) | Divides to object and it's sub-objects |
Texture | 01 00 00 00 09 (Always) | Contains one .TIM texture |
Info/Script
Currently unknown, takes up to ~1400 bytes from start. Unused in-game. Can be null'ied and nothing happen.
Camera data
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Number of cameras |
2 | 2 bytes | Number of camera animations? |
?? / Camera data | Varies | Currently unknown |
Camera data contains:
- Prekeyed camera movement
- Camera zoom
- Camera FOV (horizontal and vertical)
- Orthogenical projection
- Rotation
- Special effects like earthquake
- More, unknown?
This file does not contain camera animations for victory, summons and etc.
Geometry
Geometry contains groups, that contains objects. Ground plane is always 1 object, so it's easy to find geometry data by searching for "Usually starting" header as seen in info section. The group contains objects and location to every start of object
Group
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Number of objects in group |
4 | 4 bytes | Position of object 1 |
8 / varies | 4 bytes | Position of next objects, if number of objects != 1 |
Object
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Always 01 00 01 00 / Header of object |
4 | 2 bytes | Uint16 / number of vertices. |
6 | Number of vertices * 6 | Vertex data, short X; short Y; short Z; |
6 + (Number of vertices *6) | (AbsolutePosition MOD 4) + 2 | Padding |
varies (just after above) | 2 bytes | uint16 / number of triangles |
varies (just after above) | 2 bytes | uint16 / number of quads |
varies (just after above) | 4 bytes | padding |
varies (just after above) | number of triangles * 20 | Triangle data. If NumOfTriangles = 0, then instead of any triangle data, there's quad data. |
varies (just after above) | number of quads * 24 | Triangle data. If NumOfQuads = 0, then instead of any quad data, there's either next header 01 00 01 00, or end of group. |
Triangle
Name | Type | Description |
---|---|---|
F1 (A) | uint16 | A of face indice |
F2 (B) | uint16 | B of face indice |
F3 (C) | uint16 | C of face indice |
U1 | Byte | U of first texture coordinate |
V1 | Byte | V of first texture coordinate |
U2 | Byte | U of second texture coordinate |
V2 | Byte | V of second texture coordinate |
OP | Byte | Opacity / Alpha channel blend |
Unknown | Byte | PSOne GPU related? |
U3 | Byte | U of third texture coordinate |
V3 | Byte | V of third texture coordinate |
Special (see below / After QUAD table) | 8 Byte | See below (after QUAD table) |
Hide | Byte/Bool | Bool. Hides or shows texture |
Red | Byte | Texture colourization (Red) |
Green | Byte | Texture colourization (Green) |
Blue | Byte | Texture colourization (Blue) |
PSone GPU related | Byte | PSOne instruction |
Quad
Name | Type | Description |
---|---|---|
F1 (A) | uint16 | A of face indice |
F2 (B) | uint16 | B of face indice |
F3 (C) | uint16 | C of face indice |
F4 (D) | uint16 | D of face indice |
U1 | Byte | U of first texture coordinate |
V1 | Byte | V of first texture coordinate |
OP | Byte | Opacity / Alpha channel blend |
Unknown | Byte | PSOne GPU related? |
U2 | Byte | U of second texture coordinate |
V2 | Byte | V of second texture coordinate |
Special (see below) | 8 Byte | See below (after table) |
Hide | Byte/Bool | Bool. Hides or shows texture |
U3 | Byte | U of third texture coordinate |
V3 | Byte | V of third texture coordinate |
U4 | Byte | U of fourth texture coordinate |
V4 | Byte | V of fourth texture coordinate |
Red | Byte | Texture colourization (Red) |
Green | Byte | Texture colourization (Green) |
Blue | Byte | Texture colourization (Blue) |
PSone GPU related | Byte | PSOne instruction |
Special Byte: This byte, needs to be divided to two bytes. So, for example, a 0xE5 needs to be treated like two bytes: 0x0E 0x05 Other way is to treat first one as 6 BIT's, and second one as 2 BIT.
Singular of char | Example | Description |
---|---|---|
First char/ 6 BIT's | B2 --> 0B | Unknown |
Second char / 2 BIT | B2 --> 02 | Texture page number. |
Texture
Contains one TIMs with various size 512x256, 673x256, 768x256 (8BPP).
UV calculation algorithm
Float U = (float)U_Byte / (float)(TIM_Texture_Width * 2) + ((float)Texture_Page/(TIM_Texture_Width * 2));
Texture page calculation
string StrByte = InputBytes[TexturePage_index].ToString("X2"); //Gets TPage byte as HEX text StrByte = "0" + StrByte.Substring(1); // Deletes the first char/ 6 bits Byte TPage = Byte.Parse(StrByte); // Parses result as new byte int TPageINT = TPage * 128; //For 8 bit TIM's, the texture page is 128 sized
Example: 0xB2 byte is: 2*128 = 256
TIM Texture width/height resolving
Byte[] OPN = File.ReadAllBytes(@"PATH TO .X stage file"); //Change this Byte[] TIMtexture = { 0x10, 0x00, 0x00, 0x00, 0x09 }; int TIMoffset = ByteSearch(OPN, TIMtexture, 0); //Byte search is special search for byte array custom function int TIMoffsetCLUTetc = TIMoffset + 18; Byte[] CLUT = new byte[2]; Array.Copy(OPN, TIMoffsetCLUTetc, CLUT, 0, 2); UInt16 CLUTsize = BitConverter.ToUInt16(CLUT, 0); //DETERMINE HOW MUCH TO PASS TIMoffsetCLUTetc += 2 + (CLUTsize * 512) + 8; Byte[] szer = new byte[2]; Byte[] wyso = new byte[2]; Array.Copy(OPN, TIMoffsetCLUTetc, szer, 0, 2); Array.Copy(OPN, TIMoffsetCLUTetc + 2, wyso, 0, 2); UInt16 szerU = BitConverter.ToUInt16(szer, 0); UInt16 wysoU = BitConverter.ToUInt16(wyso, 0); int newSzerU = szerU * 2;