Formats/SSXTricky:MPF(PS2 Model)
Overview
An MPF file contains model names, bones, UV maps, normals, vertices and other model data.
Here is the structure made in programming languages for easy code implementation:
- SSX Tricky MPF C# handler by GlitcherOG
- [SSX Tricky mpf GO struct by Erick](https://github.com/Erickson400/TheTrickyModels/blob/main/mpf/MpfStructure.go)
Structure
File Header
Section 0 - Bytes[12]
Type | Description |
---|---|
Byte[4] | Version ID (Version 8) |
UInt16 | Model Header Count |
UInt16 | Offset To Model Headers |
UInt32 | Offset To Model Data List Start |
Model Header
All Offsets Within the file are relative to the start of the Model Data
Type | Description |
---|---|
Bytes[16] | Name of Model (ASCII string with a max length of 16 bytes) |
UInt32 | Offset to Model Data which is relative to Model Data List Start Offset |
UInt32 | Size of model in bytes |
UInt32 | Offset of **Bone Data List** |
UInt32 | Offset of **IK Point List** |
UInt32 | Offset of **Mesh Group Offset** |
UInt32 | Offset of **Mesh Data** |
UInt32 | Offset Of **Material Data** |
UInt32 | Offset of Weight List Reference |
UInt32 | Offset of Bone Weights |
Byte[8] | Unused/Filler |
UInt16 | Num of Bone Weights |
UInt16 | Num of Weight List Refrence |
UInt16 | Num Of Mesh Groups |
UInt16 | Num Of Bone Data |
UInt16 | Num Of Materials |
UInt16 | Num Of IK Points |
UInt16 | Num Of Morph Keys |
UInt16 | Internal File ID. This is used in conjunction with weights so that it can access bones within another file |
Byte[4] | Filler/Padding |
Model Data
All Offsets Unless Stated Otherwise are relative to the start of each model data
Material Data
Unused Slots use 0x00202020 as a place holder
Type | Description |
---|---|
Bytes[4] | Name of Main Texture map/file |
Bytes[4] | Name/Type of Texture (Unused In PS2) |
Bytes[4] | Name/Type of Texture (Unused In PS2) |
Bytes[4] | Name/Type of Texture (Used To Tell Game If Material Has Gloss **_g) |
Bytes[4] | Name/Type of Texture (Used To Tell Game If The Object uses Environment Reflection envr) |
Float32 | Flag Factor |
Float32 | Unknown float value |
Float32 | Unknown float value |
Bone Data
Location and Rotation are relative to parent
Type | Description |
---|---|
Bytes[16] | Name of Bone (ASCII string with a maximum length of 16 bytes) |
UInt16 | Internal File ID of Parent Bone(First bone always has 0xFFFF) |
UInt16 | ID of Parent Bone (First bone always has 0xFFFF) |
UInt16 | Bone ID (?) |
UInt16 | Unknown |
Vector 3 (3 Float32s) | XYZ Position Of the Bone |
Vector 3 (3 Float32s) | XYZ Radian Rotation of the bone |
Vector 3 (3 Float32s) | XYZ Radian 2 |
6 Float32s | 6 Floats either being -1 or 1 |
IK Points
Type | Description |
---|---|
Vector 3 (3 Float32s) | Location XYZ |
UInt32 | Unknown (Filler) |
Group Main
Group Main Header
Type | Description |
---|---|
UInt32 | Group Type (1 Standard, 17 Shadow, 256 Morph) |
UInt32 | Material ID |
UInt32 | Unknown (Always -1) |
UInt32 | Weight Reference Group Offset |
UInt32 | Weight Reference Group Count |
Weight Reference Group
Type | Description |
---|---|
UInt32 | Mesh Group Offset |
UInt32 | Mesh Group Count |
Mesh/Morph Data Group
Each one of these in order references a Weight Reference and all points within it will use that weight reference
Type | Description |
---|---|
UInt32 | Model Offset |
UInt32 | Morph Target Offset Relative to Model Offset |
UInt32 | Morph Target Entry Size |
Bone Weight
Bone Weight Header
Type | Description |
---|---|
UInt32 | Length of array/list |
UInt32 | Offset to Bone weight list |
UInt32 | Unknown (Always 36) |
Bone Weight
Type | Description |
---|---|
UInt16 | Bone weight (0 to 100) |
UInt8 | Bone ID |
UInt8 | Bone Internal File ID |
Weight List Ref
Type | Description |
---|---|
UInt32 | Weight Reference Count |
UInt32 | Weight Reference Offset |
Int32 List | WeightIDs |
Mesh Data
The mesh data within the mpf can be very complex and is chunked meaning there can be multiple data chunks within a Mesh/Morph Data Group
Depending on the group type (Located in the mesh group) can effect what information is in here.
- If Group Type is Standard there will be UV/Weight Block, Normal Block and, Vertex Block.
- If Group Type is Shadow There will be Shadow Vertex Block
- If Group Type is Morph the data will be the same as standard however there will be no data chunking
Bytes[48] Unimportant Data for Exporting
Type | Description |
---|---|
UInt32 | Strip Count |
UInt32 | Starting Weight Ref ID (Generally Always 14) |
UInt32 | Unknown2 (If group type is shadow this will be 0) |
UInt32 | Vertex Count |
Tristrip Data
Type | Description |
---|---|
UInt32 | Count of vertices |
Bytes[12] | Padding |
UV/Weight Block
Type | Description |
---|---|
Bytes[16] | Header of UV Block (Hex: 00100000 00100000 00000020 50505050) |
Bytes[12] | Unknown |
Byte | Unknown |
Byte | Prefix List Start (0x80) |
Byte | Count of UVs |
Byte | Suffix of UV count (0x6D) |
List of UV value | List Of UV/Weights Values |
UV value
Type | Description |
---|---|
UInt16 | UV map U (X translation) (In order to get the float value you do Number / 4096) |
UInt16 | UV map V (Y translation) (In order to get the float value you do Number / 4096) |
UInt16 | Bone Weight Ref ID (In order to get ID you do (Number - 14)/4) |
Uint16 | Bone Weight Ref ID (In order to get ID you do (???)) |
Normal Block
Type | Description |
---|---|
Bytes[16] | Header of normal Block (Hex: 00000000 00800000 00000020 40404040) |
Bytes[12] | Unknown |
Byte | Unknown |
Byte | Prefix List Start (0x80) |
Byte | Count of Normals |
Byte | Suffix of Normal count (??) |
List of Vector 3 (3 Int16s) | List of normals (In order to get the float value you do Number / 4096(???)) |
Vertex Block
Type | Description |
---|---|
Bytes[16] | Header of Vertex Block (Hex: 00000000 0000803F 00000020 40404040) |
Bytes[12] | Unknown |
Byte | Unknown |
Byte | Prefix List Start (0x80) |
Byte | Count of Vertices |
Byte | Suffix of Vertex count (0x78) |
List of Vector 3 (3 Float32) | List Of Vertex values |
Shadow Vertex Block
Type | Description |
---|---|
Bytes[16] | Header of Vertex Block (Hex: 00000000 0000803F 00000020 40404040) |
Bytes[12] | Unknown |
Byte | Unknown |
Byte | Prefix List Start (0x80) |
Byte | Count of Vertices |
Byte | Suffix of Vertex count (??) |
List of Shadow Vertex | List Of Shadow Vertex values |
Shadow Vertex value
Type | Description |
---|---|
Vector 3 (3 Float32) | Location XYZ |
Uint16 | Bone Weight Ref ID (In order to get ID you do (Number - 14)/4) |
public int U1;
public int HeaderCount;
public int HeaderOffset;
public int FileStart;
public List<MPFModelHeader> ModelList = new List<MPFModelHeader>();
public struct MPFModelHeader
{
//Main Header
public string FileName;
public int DataOffset;
public int EntrySize;
public int BoneDataOffset;
public int IKPointOffset;
public int MeshGroupOffset;
public int MeshDataOffset;
public int MaterialOffset;
public int NumberListOffset;
public int BoneWeightOffet;
//Counts
public int BoneWeightCount;
public int NumberListCount;
public int MeshGroupCount;
public int BoneDataCount;
public int MaterialCount;
public int IKCount;
public int MorphKeyCount;
public int FileID;
public List<MaterialData> materialDatas;
public List<BoneData> boneDatas;
public List<Vector3> iKPoints;
public List<GroupMainHeader> MeshGroups;
public List<BoneWeightHeader> boneWeightHeader;
public List<WeightRefList> numberListRefs;
}
public struct WeightRefList
{
public int SubCount;
public int Offset;
public List<int> WeightIDs;
}
public struct MaterialData
{
public string MainTexture;
public string Texture1;
public string Texture2;
public string Texture3;
public string Texture4;
public float FactorFloat;
public float Unused1Float;
public float Unused2Float;
}
public struct BoneData
{
public string BoneName;
public int ParentFileID;
public int ParentBone;
public int Unknown2;
public int BoneID;
public Vector3 Position;
public Vector3 Radians;
public float XRadian2;
public float YRadian2;
public float ZRadian2;
public float UnknownFloat1;
public float UnknownFloat2;
public float UnknownFloat3;
public float UnknownFloat4;
public float UnknownFloat5;
public float UnknownFloat6;
public int FileID;
public int BonePos;
}
public struct GroupMainHeader
{
public int GroupType; //1 Standard, 17 Shadow, 256 Morph
public int MaterialID;
public int Unknown;
public int LinkCount;
public int LinkOffset;
public List<WeightRefGroup> meshGroupSubs;
}
public struct WeightRefGroup
{
public List<int> weights;
public int LinkOffset;
public int LinkCount;
public List<MeshMorphHeader> MeshGroupHeaders;
}
public struct MeshMorphHeader
{
public int ModelOffset;
public int MorphKeyOffset; //Morph Target Offset
public int MorphKeyEntrySize; //Morph Target Entry Size
public int WeightRefGroup;
public List<MeshChunk> staticMesh;
public List<MorphKey> MorphKeyList;
}
public struct MorphKey
{
public int MorphPointDataCount;
public List<Vector3> morphData;
}
public struct BoneWeightHeader
{
public int Length;
public int WeightListOffset;
public int unknown; //Always 36
public List<BoneWeight> boneWeights;
}
public struct BoneWeight
{
public int Weight;
public int BoneID;
public int FileID;
}
public struct MeshChunk
{
public int StripCount;
public int Unknown1;
public int Unknown2;
public int VertexCount;
public List<int> Strips;
public List<Vector4> uv;
public List<Vector3> vertices;
public List<int> Weights;
public List<Face> faces;
public List<Vector3> uvNormals;
public List<MorphKey> MorphKeys;
}