KCL (File Format)/Wii U

From Wexos's Wiki
Revision as of 17:37, 1 May 2024 by Wexos (talk | contribs) (Imported from avsys wiki)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigationJump to search

KCL files are collision files, which is the model the game runs collision against. KCL files has been used since at least Mario Kart DS, but this documentation is about the format used in Wii U and Nintendo Switch. For other formats, see KCL (File Format).

KCL stores prisms, a triangle with a depth, in a format which allows fast access and collision calculation, and has an octree which splits the world space into many sub spaces, to make the game test collision on less prisms, which allows for much faster collision detection.

File Format

Header

The file begins with the following header:

Offset Type Description
0x00 Byte[4] Version number. Always 2.2.0.0.
0x04 UInt32 Division info offset.
0x08 UInt32 Model offset table offset.
0x0C UInt32 Number of models.
0x10 Float[3] Minimal coordinate for all models.
0x1C Float[3] Maximal coordinate for all models.
0x28 Int32[3] Area width shift. Defines the size of the space where collision data is stored.
0x34 UInt32 Total number of prisms.

Division Info

The collision files of Mario Kart 8 actually hold multiple models in the format of those found in Mario Kart Wii. This was required because one of such models can only hold a maximum of 16384 prisms, because each prism requires four normal vectors, and it can only link to 65536 normals.

Instead of increasing the size used to store a prism index, multiple such models are stored, of which each represents the prisms available in one, or multiple, cubes of the whole course space. To divide the course space into such cubes referencing the models, a new global division follows the header. It works similar to the octree of one of such models, but instead of looking up prisms, models are looked up with it.

The division info consists of at least 8 integers, representing the division keys of the 8 cubes the course space is initially divided into. Depending on the flags set in the upper two bits of the key, either the remainder points to an index of a model in the model array which data will be used for this cube, divides the cube further into 8 subcubes, or denotes no data being available in this cube.

Set Flags (0-based) Remaining Data Description
31 Model Index Model index which is part of this space.
31 & 30 Unused (being 0) No model is used for this cube, as no data is present in this part of space.
else Child Nodes Offset Divides this cube into 8 more subcubes. The value is an offset, which is multiplied by 4 to get the actual offset, relative to the start of the current node.

Model

Each model in the file has a format almost identical to KCL files in Mario Kart Wii. The model consists of a header, and four data sections. The header is a 0x3C byte structure as follows:

Offset Type Description
0x00 UInt32 Vertex position offset, relative to the start of this structure.
0x04 UInt32 Normal offset, relative to the start of this structure.
0x08 UInt32 Prism offset, relative to the start of this structure.
0x0C UInt32 Octree offset, relative to the start of this structure.
0x10 Float Prism thickness. Defines the depth of the prisms created by the triangles.
0x14 Float[3] Minimum coordinates of this model, which also is the octree origin.
0x20 UInt32 X width mask.
0x24 UInt32 Y width mask.
0x28 UInt32 Z width mask.
0x2C UInt32 Block width shift.
0x30 UInt32 Blocks X shift.
0x34 UInt32 Blocks XY shift.
0x38 Float Sphere radius. Unknown usage.

Vertex Position

This section is an array of vertex positions, each represents as three floats, X, Y and Z. The number of elements is not stored.

Normals

This section is an array of normals, each represents as three floats, X, Y and Z. The number of elements is not stored.

Prisms

The third section is the section containing the actual model information. The structure of each entry in this section is a 0x14 byte structure given below.

Offset Type Description
0x00 Float Triangle height.
0x04 UInt16 The index of the base vertex position into the vertex array.
0x06 UInt16 The index of the triangle normal into the normal array.
0x08 UInt16 The index of the prism side A normal into the normal array.
0x0A UInt16 The index of the prism side B normal into the normal array.
0x0C UInt16 The index of the prism side C normal into the normal array.
0x0E UInt16 Collision attribute.
0x10 UInt32 Global prism index.
File:KCL Prism Description.png
A collision prism.


Below contains the calculation needed to convert three vertices into the needed values. This method assumes the vertices are arranged anti-clockwise when viewed from the collidable side.

Position = Vertex1
Direction = Normalize(Cross(Vertex2 - Vertex1, Vertex3 - Vertex1 ))
DirectionA = Normalize(Cross(Normal, Vertex3 - Vertex1 ))
DirectionB = Normalize(-Cross(Normal, Vertex2 - Vertex1 ))
DirectionC = Normalize(Cross(Normal, Vertex2 - Vertex3 ))
Length = Dot(Vertex2 - Vertex1, DirectionC )

Octree

The octree subdivides the world space into cubes, to allow much faster prism collision detection. The number of root nodes can be calculated by the following algorithm:

NrRootNodes = (MaskWidthX >> BlockWidthShift + 1) * (~MaskWidthY >> BlockWidthShift + 1) * (~MaskWidthZ >> BlockWidthShift + 1)

Then the number of root nodes are written to the file. These nodes link to more nodes or prism lists.

Node

Each node has the following structure:

Offset Type Description
0x00 UInt32 Flag: ABBB BBBB BBBB BBBB BBBB BBBB BBBB BBBB

A: 1 means it's a leaf. See below.
B: Offset to next structure, relative to the parent node, or start of octree data if the node is a root node.

If the node is a leaf, then it means it isn't subdivided anymore and it contains a prism list. This prism list is terminated by 0xFFFF, and contains indices of the prisms that are present in this subspace. If it's not a leaf, then this node is subdivided into 8 more nodes, which the offset into the structure links to.

Tools

The following tools can handle KCL files: