I know there are already several topics about this around here in tech-related, however, I don't want to resurrect one of them. And I think someone might have made some progress here.
As most of you surely know, the FF7 .p model format has been decoded quite far, but not to 100%.
Qhimm has started hacking the .p format, ficedula did another step, and after some time, I wrote the first FF7 .p Editor, Ultima. This was 4 years ago.
There has been much progress made, especially in texturing.
I don't have the latest copy of gears here, but I think the .p description was taken from my last description, and mirex's latest description.
In the last time, some FF7 viewers and even editors have appeared. Yes, I talk about
Kimera.
However, AFAIK, I'm the only one who was able to generate a .p file from scratch that FF7 accepted (unfortunately, this model was just a coloured triangle without textures)
Okay, the aim of this topic is to collect as much info as possible about the .p Format to be able to build "real" .p models from scratch.I already have an idea how to do this, however,
there is still one part of the file which I know almost nothing about - the hundrets thingy...This post is going to be a big quote from my .p File Description, however, I have tried to correct some minor bugs here.
Notation:
All offsets are hex-decimal, all sizes are decimal.
First, here comes the table of contents of this topic:
Chapter 0: Table of Contents.p-File
|
+- Header
|
+- Vertices[]
|
(+- Normals[]) ( Field-Files only)
|
(+- Texture Coords[]) (Textured models only)
|
+- Vertice Colors[]
|
+- Polygon Colors[]
|
+- Edges[]
|
+- Polygons[]
|
+- Hundrets[]
|
+- Groups[]
|
+- BoundingBox
|
+- Normal Index Table[]
Chapter I.i: The File HeaderThe structure:
typedef struct
{
long off00;
long off04;
long VertexColor;
long NumVerts;
long NumNormals;
long off14;
long NumTexCs;
long NumNormInds;
long NumEdges;
long NumPolys;
long off28;
long off2c;
long mirex_h;
long NumGroups;
long mirex_g;
long off3c;
} t_p_header; // 64 Bytes
Interpretation:
VertexColor specifies if Vertex-Colors are used
(0=no,1=yes; default: 1)
NumVerts Count of Vertices
NumNormals Count of Normals (always 0 in Battle files)
NumTexCs Count of Texture Coords
NumNormInds Count of Normal Indices
NumEdges Count of Lines for WireFrame-Model
NumPolys Count of Polygons
mirex_h Count of Hundrets
NumGroups Count of Groups
mirex_g ? (sometimes 0 or 1)(but usually 1)
Chapter I.ii: The Extended HeaderMisterious name for something maybe banally simple.
This is just an array of 16 32-Bit Integers. We have never been able to decode this 64 byted, however, I suppose this is some kind of checksum for the single parts of the .p file.
I don't remember what happens when you change all those values to 0, but IIRC, FF7 *should* accept those files without crashing... but I'm not sure.
Chapter II: The VerticesThe vertex structure:
typedef struct
{
float x;
float y;
float z;
} t_p_vertex; // 12 bytes
Offset: 0x80
Number of Entries: NumVerts;
I don't think that I have to add anything here. It's trivial.
Chapter III. The Normals (Field Files only)The normal structure is exactly the same as the vertex structure.
Offset: 0x80 + (NumVerts * 12)
Number Of Entries: NumNormals;
I don't remember what they're normal to, but I think they're normal to the vertices...
Chapter IV: The Texture CoordinatesStructure:
typedef struct
{
float x;
float y;
} t_p_texturecoord; // 8 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12
Number Of Entries: NumVerts
x and y are the offsets on the texture relative to the texture size.
The values can between 0.0 and 1.0. So if a TexCoord has x = 0 and x = 0, it is in the upper left corner, if it has x = 1 and y = 1 it is in the
lower right corner (or at least I hope so...)
Simetimes, the values may be even higher than 1.0. In that case, i.e. 1.3
is the same as 0.3. So if a value exceeds 1.0, simply subtract 1.0 from
it.
Chapter V: Vertice ColorsStructure:
typedef struct
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
} t_p_color; // 4 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8)
Number Of Entries: NumVerts
Every Vertex has its own color stored here.
Chapter VI: Polygon ColorsThe structure is the same as the vertex color one.
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + NumVerts * 4
Number Of Entries: NumPolys
Every Polygon has its color stored here.
Chapter VII: EdgesStructure:
typedef struct
{
unsigned short Vertex[2];
} t_p_edge; // 4 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + (NumVerts + NumPolys) * 4
Number Of Entries: NumEdges
The edges build up the wireframe of the model. Every edge connects 2 vertices of the model.
Chapter VIII: PolygonsStructure:
typedef struct
{
unsigned short Tag1;
unsigned short Vertex[3];
unsigned short Normal[3];
unsigned short Edge[3];
unsigned long Tag2;
} t_p_polygon; // 24 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + (NumVerts + NumPolys + NumEdges) * 4
Number Of Entries: NumPolys
Interpretation:
Tag Unknown, but always 0
Vertex[*] Index of Vertex * for the polygon
Normal[*] Index of Normal* for the polygon (always 0 in Battle Files)
Edge[*] Index of Edge * for WireFrame-Model
Tag2 Unknown, but always 0x0CFCEA00
Note: The Normal Indices are absolute, not relative to the Group!
Chapter IX: HundretsA very ugly Structure:
typedef struct
{ // 1st 2nd 3rd
long off00; // 0x00000001
long off04; // 0x00000001
char off08; // 0x00
char off09; // 0x82 0x86 0x86
short off0a; // 0x0003
char off0c; // 0x02
char off0d; // 0x00 0x04 0x04
short off0e; // 0x0002
long off10; // 0x00000000 0x00000000 0x00000001
long off14; // 0x00000000
long off18; // 0x00000000 0x00000001 0x00000001
long off1c; // 0x00000000 0x00000025 0x00000025
char off20; // 0x00 x00 x40 x80 x00 x40 x80
char off21; // 0x00 0x78 0x78
short off22; // 0x0000
long off24; // 0x00000002 0x00000001 0x00000001
long off28; // 0xFFFFFFFF
long off2c; // 0x00000000
long off30; // 0x00000000
long off34; // 0x00000002 0x00000005 0x00000005
long off38; // 0x00000001 0x00000006 0x00000006
long off3c; // 0x00000002
long off40; // 0x00000000
long off44; // 0x00000004 0x00000000 0x00000000
long off48; // 0x00000000
long off4c; // 0x00000000
long off50; // 0x00000000
long off54; // 0x00000000
long off58; // 0x00000000
long off5c; // 0x000000FF 0x00000080 0x00000080
long off60; // 0x00000000
} t_p_hundrets; // 100 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + (NumVerts + NumPolys + NumEdges) * 4 + (NumPolys * 24)
Number Of Entries: Mirex-H
I don't really know what is stored here, but I suppose it has to do with
the textures... well, dunno.
In the C/C++ Struct, there is the info how this struct is usually filled.
So if you want to create a new Hundrets Entry, you could use these
values.
I could really need some help of this part, if someone has any ideas...
Chapter X: GroupsStructure:
typedef struct
{
long polyType;
long offPoly;
long numPoly;
long offVert;
long numVert;
long offEdge;
long numEdge;
long off18; // 0
long off1c; // 0
long off20; // 0
long off24; // 0
long offTex;
long texFlag;
long texID;
} t_p_group; // 56 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + (NumVerts + NumPolys + NumEdges) * 4 + (NumPolys * 24) +
Mirex-H * 100
Number Of Entries: NumGroups
Interpretation:
polyType: Specifies the Polygon Type for this Group:
1 - nontextured Polygons
2 - textured Polygons with normals
3 - textured Polygons without normals
offPoly: The First Polygon used in this Group
numPoly: Number of Polygons used in this Group
offVert: see above
numVert: see above
offEdge: The First Edge used in this Group
numEdge: see below
offTex: The first Texture Coord used in this Group
texFlag: Texture Flag:
0 - No texture on this Group
1 - Textured
texID: Index of Texture (see below)
Now it's gettin' more complicated... The numEdge value is usually 0.
So if you want to know how many Edges are used in Chunk i, then you'll
have to see the offEdge in Chunk i+1 and get the difference ... blabla ...
ahhh, take a look at this:
t_p_group
.numEdge = t_p_group[i+1].offEdge - t_p_group.offEdge
BUT: If you want to get the numEdge for the LAST Group, then, of course,
you'll have to do this:
t_p_group.numEdge = t_header.NumEdges - t_p_group.offEdge
I hope you know what I mean.
BTW: If you're going to generate you own Groups, you CAN save the numEdge
values to the struct; FF7 won't crash.
As for the texID entry:
In Field files, this is the Index used by the RSD Files.
In Battle files it *should* be like this:
(Example: Yuffie: RX**)
1 - rxac
2 - rxad
3 - rxae
...
Chapter XI: Bounding Box
Structure:
typedef struct
{
float max_x;
float max_y;
float max_z;
float min_x;
float min_y;
float min_z;
} t_p_boundingbox; // 24 Bytes
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + (NumVerts + NumPolys + NumEdges) * 4 + (NumPolys * 24) +
(Mirex-H * 100) + (NumGroups * 56) + 4
Number of Entries: 1
Chapter XII: Normal Index TableThe entries in the Normal index table are just 32-bit unsigned integers.
Offset: 0x80 + (NumVerts + NumNormals) * 12 + (NumTexCs * 8) + (NumVerts + NumPolys + NumEdges) * 4 + (NumPolys * 24) +
(Mirex-H * 100) + (NumGroups * 56) + 4 + 24
Number Of Entries: NumNormInds
Interpretation:
Heh, it took me a long time top hack these values, too!
But it's quite simple! This is just a normal index table!
It's just an array of 32Bit integers.
That means if you want to know which normal is used by vertex *, you
will have to take a look into that table.
So let's say:
NormalIndex[0] = 4
NormalIndex[1] = 7
NormalIndex[2] = 2
...
So the Vertex 0 uses Normal 4,
... Vertex 1 uses Normal 7,
... Vertex 2 uses Normal 2,
and so on...
That's it. If you have any corrections or additions to make, please let me know. I'll update this post then ASAP.
- Alhexx