Add *pet utilities
pixeldesu opened this issue · comments
There are a vast amount of file types related to models and animation, namely:
*.pet
*.apet
*.bpet
*.mpet
Handling all file types also involves these files of course, so we need fitting utilities and documentation for them!
Some research on (m)pet files and structures included inside them:
According to @hsreina there seem to be various different versions of *pet files, some easier being denoted by having the VERS
section with a version number. Without that, you can just deem it "legacy".
Structures and current research:
General
All of the structures have one thing in common, the first integer after the 4-length char denoting the structure (e.g. TEXT
) is the size of the whole structure and then usually a count of how many entries there are in the specific section.
Textures - TEXT
struct Texture {
string Name; // null-terminated (?)
// there's quite a bit more unknown data here, texture maps maybe?
}
Bones - BONE
struct Bone {
string Name; // null-terminated
byte Parent; // ID of the parent element
float[12] Matrix; // Bone-matrix data, matching up with perspective projection
}
Perspective projection: https://en.wikipedia.org/wiki/3D_projection#Perspective_projection
Mesh - MESH
The first count of this structure is for the number of vertices of the mesh.
struct Vertex {
float x;
float y;
float z;
BoneInformation[] BoneInformation;
}
The array of BoneInformation
structures continues until all Weight
attributes accumulated have a sum of 0xFF
.
struct BoneInformation {
byte Weight;
byte BoneID;
}
After the vertices, the next integer following denotes the number of Polygons.
struct Polygon {
PolygonIndex[3] Indices;
}
Each Polygon
contains 3 PolygonIndex
structures. These contain the position inside the 3D space (x
, y
, z
) and information for the UV mapping of the textures (u
, v
)
struct PolygonIndex {
float x;
float y;
float z;
float u;
float v;
}
Motion - MOTI
struct Motion {
uint nameLength;
string name; // read nameLength bytes
uint motionStart;
uint motionEnd;
uint typeNameLength;
string typeName; // read typeLength bytes
uint type; // looks to be null usually
uint boneNameLength;
string boneName; // read boneNameLength bytes
}
Collision Boxes - COLL
struct CollisionBox {
uint u1;
uint u2;
uint nameLength;
string name;
uint boneNameLength;
string boneName;
byte u3; // some kind of bool flag, I guess?
uint u4;
uint u5;
float minx;
float miny;
float minz;
float maxx;
float maxy;
float maxz;
}
Animation - ANIM
TODO
Face Animation - FANM
TODO
??? - FRAM
TODO - Most of the files that includes this only show an empty section here.
??? - SMTL
Only included in files with a VERS
section.
TODO - Most of the files that includes this only show an empty section here.
The texture is more like that
struct Vertex {
char matName[0x20];
char name[0x20];
unsigned int un1;
unsigned int un2;
unsigned int un3;
}
un1, un2, un3 are important, but I never searched too much about them. But you can add a specular effect to the model by add a texture with those params after the other textures
texture.un1 = 0x00460001;
texture.un2 = 0xFFFFFFFF;
texture.un3 = 0x00000001;
texture.name[0] = 0;
texture.matName[0] = 0;
strcat(texture.name, "!specular_ellipse_md.jpg");
It's used to make some items more shiny.
You also have the VERS chunk who is not present on all puppet files.
It help to detect version changes on the puppet files.
there were some changes in some chunks based on those versions
Structure is as follow:
struct TPuppetVersion{
unsigned char Minor; // 0x01, 0x02, 0x03
unsigned char Major; // 0x01
unsigned char c; // 0xFE
unsigned char d; // 0xFF
};
I always considered Puppets with no VERS chunk in it as legacy version 1.0
So the current existing versions are
1.0
1.1
1.2
1.3
Some more stuff I just found out, quickly skimming over it:
Motion - MOTI
(also includes the common size
and count
values)
struct Motion {
uint nameLength;
string name; // read nameLength bytes
uint motionStart;
uint motionEnd;
uint typeNameLength;
string typeName; // read typeLength bytes
uint type; // looks to be null usually
uint boneNameLength;
string boneName; // read boneNameLength bytes
}
Edit: Adjusted this a bit as I ended up skipping a line while analyzing the values. Found two more which look like rotational information to me. For the replay tape the values for motionStart
and motionEnd
are 0
/359
, which makes up a 360 degree rotation, but on other models it's either less than that or even over 360, so I'm not entirely sure if this discovery is correct.
And more, still some unknown values inbetween, the rest makes sense tho:
Collision Box - COLL
struct CollisionBox {
uint u1;
uint u2;
uint nameLength;
string name;
uint boneNameLength;
string boneName;
byte u3; // some kind of bool flag, I guess?
uint u4;
uint u5;
float minx;
float miny;
float minz;
float maxx;
float maxy;
float maxz;
}
Added the base library PangLib.PET
and handled most of the cases written down here.
Stuff that isn't handled yet:
- Following sections:
VERS
TEXT
SMTL
ANIM
FANM
FRAM
- Some structures being different in different versions (as supplied by
VERS
), need to test the library with more pet files to figure this out
While there are still some issues in files like .apet
and the other specific ones, this is now mostly implemented and usable, as seen in https://github.com/pangyatools/PETViewer-Unity