Changes

Jump to navigation Jump to search

FF8/FileFormat X

5,775 bytes added, 21:55, 23 December 2020
m
0 Default: fix size of animation frame
! style="background:rgb(204,204,204)" | Description
|-
| Unused dataPlayStation MIPS assembly
| E8 FF BD 27 01 00 02
| This data is unused by FF8 EngineUsed only in PS version; skipped in PC
|-
| Camera data + movement
| Camera animations, movement (pre-keyed)
|-
| GeometryModel section| 01 06 00 00 01 00 (See geometry section info)
| Divides to object (group) and it's sub-objects + vert/triangle grouping
|-
| Texture
| 01 10 00 00 00 09 (Always)| Contains one .TIM texture , 8 BPP
|}
== How is this file handled by the engine? ==
FF8 loads specific file and reads it from hardcoded (written in FF8 code) position(or reads MIPS PlayStation assembly that contains battle stage load code). This hardcoded position points to camera data(in PC). Camera data has size uint16, which is calculated and relative jump is made. Just after camera, a typical section based file handling is made.
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
| 4
| uint32
| Objects group #1 (NULL?)
|-
| 8
| 20
| uint32
| Texture[unused in code]
|-
| 24
| uint32
| Texture (Double texture available?)
|-
| 28
|}
'''====Objects group:'''Group====
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" | Offset
|}
'''=====Objects list:'''List=====
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" | Offset
|}
'''=====Settings 1:'''=====
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
! style="background:rgb(204,204,204)" | Offset
== Camera data ==
Starts at ~0x5d4, operates on 4 bytes translation of X Y and Z axis(see How the engine handles this file?). Due to orthogenical view also operates camera in screen view making it possible to move camera from 2D generated screen[. TODOtext: One thing is missing- how does the camera start and structure of camera key-movement. Global parameters of camera translations are known.00509820]
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
| 0
| uInt16
| ??/ Pointers count. Fixed 2 (02 00)'''[Unused in code]'''
|-
| 2
| uInt16
| ??/ Fixed 8 Relative jump to CameraSetting. Should be (08 00)
|-
| 4
| uInt16
| UNKNOWNRelative jump to CameraAnimationCollection. Should be (20 00)
|-
| 6
| uInt16
| Camera data size (starting from 0)'''[unused in code]'''
|-
| 8
| uInt1624 bytes| Camera DataSettings|-| 32| ?? bytes| Camera Animation Collection|} ====Camera Setting==== {| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| char (based on disassembly)| CameraAnimMode?|-| 1| byte?| StopEnemyBeforeAnim?|-| 2| Bitfield? (1B)| UHM?|-| 3| ???| DefaultEndofCameraPosition_Zoom?|-| 4| ???| ???|} ====Camera Animations Collection====  {| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16| NumOfSets|-| 2 *(Set index)| uint16| Relative pointer to camera Animation Set|-| 2 *(Set index)+ 2| uint16| Camera EOF|-| CameraAnimationSetPointer| CameraAnimationSet| CameraAnimationSet|} =====CameraAnimationSet=====Seems to be 8 pointers in each set.{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-|0|ushort|AnimPointer*2 |-|AnimPointer|Varies 144-146-148 bytes usually|CameraAnimation|} == Camera Animation (WIP) == All this is based on best effort knowledge from reversing by Maki. I'm just trying to understand it.=== Control Word ==={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16_t (bit varies)| Main controller. If 0xFFFFU END|}==== FOV ==== Control Word & 0b0000'0000'1100'0000U===== 1 Default ====={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| None| None| Start = 0x200|-| None| None| End = 0x200|}===== 2 Same ====={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16_t| Start|-| 2| uint16_t| Padding|-| None| None| End = Start|}===== 2 Different ====={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16_t| Start|-| 2| uint16_t| Padding|-| 4| uint16_t| End|} ==== ROLL ==== Control Word & 0b0000'0011'0000'0000U===== 0 Unknown ===== TODO===== 1 Default ====={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| None| None| Start = 0x000|-| None| None| End = 0x000|}===== 2 Same ====={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16_t| Start|-| None| None| End = Start|}===== 2 Different ====={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16_t| Start|-| 2| uint16_t| End|} ==== LAYOUT ==== Control Word & 0b0000'0000'0000'0001U===== 0 Default ===== You'll loop through the data till the first value is less than 0. pushing back to a variable length container.{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| int16_t| if < 0 break; could be related to time of frame.|-| 2| 16 bytes| Animation Frame|} ===== 1 Other ===== TODO===Time=== Time is calculated from number of frames. You basically set starting position World+lookat and ending position, then mark number of frames to interpolate between them. Every frame is one draw call and it costs 16. Starting time needs to be equal or higher for next animation frame to be read; If next frame==0xFFFF then it's all done.=== Animation Frame ==={| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"! style="background:rgb(204,204,204)" | Offset! style="background:rgb(204,204,204)" | Length! style="background:rgb(204,204,204)" | Description|-| 0| uint16_t| is frame durations shot
|-
| 102| uInt16Vertice<uint16_t> (x,y,z)| UNKNOWNWorld
|-
| 128| uInt16uint16_t| UNKNOWN- Has something with looping/timer?is frame ending shot
|-
| 1410| Vertice<uint16_t> (Camera_data_sizex,y,z)-12| Camera Data (?)Look At
|}
=====Dependency=====  CAMERA: -Camera Settings -Camera Animation Collection (even three collections in a0stg006.x and up to 7 in a0stg101.x!) | | -Camera animation Set (Always 8 camera animations, may be empty (0xFFFF); look for example to a0stg127.x collectionId==1; there are 8 animations, but 7 of them are 0xFFFF (pointers increase by 2)) | | - Camera animation  =====Example===== a0stg006.x:<br>0x5d8 -> 02 00 08 00 20 00 # Get EOF-> *(0x5d8 + 8) -> 32# Jump to EOF -> 0x5d8 + 32 = 0x5F8 (This is now Camera Animation Collection)# Get pointer to correct anim collection. In this case we will use AnimCollectionID == 0, so: *(0x5F8 + 0*2 + 2) -> 0x0c# Jump to Anim collection data:0x5F8 + 0x0c = 0x604 (This is now Camera Animation Set)# Jump to Camera animation by cameraAnimSetID, let's take for example cameraAnimSetID == 7, so: *(0x604 + 7*2) -> 0x25E. Now carefully, jump by multiplying it by 2! ## 0x604 + (0x25E * 2) = 0xAC0 Therefore: a0stg006.x Camera animation 7 in camera collection 0 is at 0xAC0
== Geometry ==
|-
| 6 + (Number of vertices *6)
| (AbsolutePosition MOD 4) + 24
| Padding
|-
0x0E
0x05
Other way is to treat first one as 6 BIT's, and second one as 2 BIT.
{| border="1" cellspacing="1" cellpadding="3" align="center" style="border: 1px solid black; border-collapse: collapse;"
=== Texture page calculation ===
Byte TPage = InputBytes[TexturePage_index] & 0F;
Bitwise TPage byte AND 0F, to delete first 4 bits
int TPageINT = TPage * 64;
For 16 bit TIM's, the texture page is 64 pixels wide
 
====Example====
For 24-bit TIM:
0xB2 byte is: 2*48 = 96
Unsure about this one. It could be 42.667 instead of 48. It takes 1.5x the space of 16 bit. I haven't seen a file that uses 24-bit yet.
 
For 16-bit TIM:
0xB2 byte is: 2*64= 128
string StrByte = InputBytes[TexturePage_index].ToString("X2"); //Gets TPage byte as HEX text StrByte = "0" + StrByte.Substring(1); // Deletes the first char/ 4 bits Byte TPage = Byte.Parse(StrByte); // Parses result as new byte int TPageINT = TPage * 128; //For 8 -bit TIM's, the texture page : 0xB2 byte is : 2*128 sized= 256
ExampleFor 4-bit TIM: 0xB2 byte is:2*128 256 = 256512
=== TIM Texture width/height resolving === //Updated - 19.07.2015 by MaKiPL Byte[] Stage = File.ReadAllBytes(@"PATH TO .X stage file"); //Load file to memory Byte[] TIMtexture = { 0x10, 0x00, 0x00, 0x00, 0x09 }; //Initialize 8BPP header int TIMoffset = ByteSearch(Stage, TIMtexture, 0); //Search Each time you half the number of bits you double the amount of data you can store in Stage for TIM header int TIMoffsetCLUTetc = TIM + 18; // Logic pass UInt16 CLUTsize = BitConverterthe same space.ToUInt16(Stage, TIMoffsetCLUTetc); //GET CLUT size to UInt16 TIMoffsetCLUTetc += 2 + (CLUTsize * 512) + 8; // Logic pass - pass CLUT offset, to get to sensitive data UInt16 szerU = BitConverterSo the calculated Texture Page is different.ToUInt16(Stage, TIMoffsetCLUTetc); //Get raw UInt16 value of width from texture data UInt16 wysoU = BitConverter.ToUInt16(Stage, TIMoffsetCLUTetc + 2); //Get raw UInt16 height value from texture data (real) int width = szerU * 2; //Calculate real texture width (For 8BPP = width*2)
=== Face order / Translation/ triangulation ===
'''1.====Quad wing order:'''====
ABCD ---> ABDC
example:
f 1 2 4 3
'''2.====Quad triangulation face order'''====
ABDC > ABD
ACD (same for VT)
f 1 2 4
f 1 3 4
'''3.====Triangles VT order:'''====
A/T1 > A/T2
B/T2 > B/T3
C/T3 > C/T1
====Example:====
(Also with quad triangulation face order!)
f 1/1 2/2 7/4 6/3
27
edits

Navigation menu