I was looking through bully col file and try to understand how they worck. There are some similarities with GTA col formats but also some diferences. I am going to present some results of my researches here. I´ll use C/C++ syntax for data formats.
The file can be divided in FileHeader and Data, while Data can also be divided in DataHeader and DataBody.
struct FileHeader {
char signature[4];
unsigned int size;
}
-signature: specifies the version and known values are: "COLL", "COL2" and "COL3"
-size: containes the size of Data in bytes.
Here goes the DataHeader:
If version>1 unsigned short flags[2];
-flags[0]: known values are: 0x2 for "COL2" and 0x3 or 0x4 for "COL3"
-flags[1]: known values are: 0x0 for "COL2" and 0x1 for "COL3"
char name[20];
unsigned int id;
-name: every of the 20 bytes are 0x0
-id: the id of the collision model
-posibly bounding objects: 48 byte divided into 2 blocs first 16 byte posible bounding sphere and second 32 byte posible bounding box
the bounding box use the Box datatype that could look like that:
struct Box {
float min[3]
unsigned int minZero
float max[3]
unsigned int maxZero
char surface[4];
}
-min and max: could contain the position of min and max
-minZero and maxZero: always 0x0
-surface: containes the values for material, flag, brightness and light
Here goes the DataBody:
This part is stil incomplete and a lot of stuff is just aligations based on GTA col format. The structs I was able to recognise are Sphere, Vertex and Face:
struct Sphere {
float values[4];
char surface[4];
}
-values: radius and (x,y,z) position of center of the sphere
-surface: containes the values for material, flag, brightness and light
struct Vertex {
short values[3];
}
-values: vertices used for the faces. short type is used to reduce used memory, the real values of a vertex can be calculated by dividing through 128.f
struct Face {
unsigned short vertices[3];
unsigned char material;
unsigned char light;
}
-vertices: IDs of vertices from the Face(triangle)
The structure of DataBody look like:
unsigned int numSpheres;
Sphere spheres[];
unsigned int unk;
unsigned int numBoxes;
Box boxes[];
unsigned int numVertices;
Vertex vertices[];
if(numVertices%2) short pading;
unsigned int numFaces;
Face faces[];
-numSpheres: number of Spheres in the array
-spheres[]: the array of Spheres with size numSpheres
-unk: always 0x0
-numBoxes: number of Boxes
-boxes: the array of Boxes with size numBoxes
-numVertices: number of Vertices in the array
-vertices: the array of Vertices with size numVertices
-pading: always 0x0
-numFaces: number of Faces in the array
-faces: the array of Faces with size numFaces
the rest is stil to be discovered, but it look something like:
unsigned int unknownValue;
Box box;
unsigned int numUnknownStructs;
UnknownStruct unknownStructs[];
-unknownValue: no idea what it good for but known values are: 0xEF5DCB33
-box: another posible Box (quite shure it´s some kind of FaceGroup for all faces)
-numUnknownStructs: number of UnknownStructs in the array
-unknownStructs[]: the array of UnknownStructs with size numUnknownStructs (seems to be in some way related to FaceGroups
struct UnknownStruct{
void unknown[8]
unsigned short start;
unsigned short end;
}
I have realy no idea how the 8 Byte from unknown can be interpreted.