HZC (File Format): Difference between revisions

From Wexos's Wiki
Jump to navigationJump to search
(Completed documentation for the rest of the found versions)
 
(2 intermediate revisions by the same user not shown)
Line 10: Line 10:
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|-
| 0x00 || UInt16 || '''[[#Version List|Version number]]'''.
| 0x00 || UInt16 || '''[[#Version List|Version number]]'''. The low byte is the minor version, and the high byte is the major version (always 1).
|-
|-
| 0x02 || UInt16 || '''Number of vertices''' ('''V''').
| 0x02 || UInt16 || '''Number of vertices''' ('''V''').
Line 17: Line 17:
|-
|-
| 0x06 || UInt16 || '''Number of custom attributes''' ('''A''').
| 0x06 || UInt16 || '''Number of custom attributes''' ('''A''').
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] ≥ 1.18'''
|- bgcolor="#DDFFDD"
| 0x08 || UInt16 || {{Unknown-left|'''Vertex extra count''' ('''VE'''), unknown exact meaning. Usually equal to '''V''' or 0.}}
|- bgcolor="#FFAAAA"
| colspan="3" align="center" | '''If version ≥ 1.23'''
|- bgcolor="#FFDDDD"
| 0x0A || Byte[10] || {{Unknown-left|'''Unknown'''.}}
|}
|}


== Vertex Data ==
== Vertex Data ==
Followed by the header, there's plain vertex position data stored as a sequence of groups of 3 Int32s (one per axis). The values are divided by 1024.
Followed by the header, there's plain vertex position data stored as a sequence of groups of 3 values (one per axis). On the DS versions, the values are integers and need to be divided by 4096.


{| class="wikitable"
{| class="wikitable"
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] ≥ 1.18'''
|- bgcolor="#DDFFDD"
| 0x00 || Float32[3]['''V'''] || '''Vertex XYZ coordinates'''.
|- bgcolor="#FFAAAA"
| colspan="3" align="center" | '''Else'''
|- bgcolor="#FFDDDD"
| 0x00 || Int32[3]['''V'''] || '''Vertex XYZ coordinates'''.
| 0x00 || Int32[3]['''V'''] || '''Vertex XYZ coordinates'''.
|}
|}
Line 38: Line 52:


== Triangle Normal Data ==
== Triangle Normal Data ==
Directly after the triangle indices there are the triangle's face normals, consisting of 3 Int32s per triangle. They seem to match the cross product of the triangle's first two edges with a magnitude of 4096.
'''Versions 1.3 and 1.5 only'''. Directly after the triangle indices there are the triangle's face normals, consisting of 3 Int32s per triangle that divide by 4096. They seem to match the cross product of the triangle's first two edges with a magnitude of 4096.


{| class="wikitable"
{| class="wikitable"
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] == 1.3 OR 1.5'''
|- bgcolor="#DDFFDD"
| 0x00 || Int32[3]['''T'''] || '''Triangle XYZ normals'''.
| 0x00 || Int32[3]['''T'''] || '''Triangle XYZ normals'''.
|}
== Triangle Adjacency Data ==
'''Version 1.5 only'''. Directly after the triangle normals there is an additional set of 3 UInt16s per triangle. The values appear to be the indices of the three neighboring triangles, with 0xFFFF for open edges.
{| class="wikitable"
! Offset !! Type !! Description
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] == 1.5'''
|- bgcolor="#DDFFDD"
| 0x00 || UInt16[3]['''T'''] || '''Neighbor triangle indices'''.
|}
== Vertex Extra Data ==
'''Versions 1.18 and up only'''. After the triangle data there is a block of '''VE''' x 4 bytes. The purpose is not fully known, but the values are commonly <code>01 01 01 01</code> per entry. This block is absent when '''VE''' is 0.
{| class="wikitable"
! Offset !! Type !! Description
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] &ge; 1.18'''
|- bgcolor="#DDFFDD"
| 0x00 || UInt32['''VE'''] || {{Unknown-left|'''Unknown'''.}}
|}
|}


== Grid ==
== Grid ==
Followed by the triangle normal data, there's a spatial grid consisting of 3D cells used for better collision detection. Each cell corresponds to an index to the [[#Linked List Array|Linked List Array]].
A spatial grid of 3D cells is used for faster collision detection. Each cell holds an index into the [[#Linked List Array|Linked List Array]], or 0xFFFF when the cell is empty. The grid is made of three blocks: the cell array, the [[#Grid Info|Grid Info]], and the [[#Linked List Array|Linked List Array]]. On versions 1.22 and up the order is reversed (the Linked List Array comes first, then the Grid Info, and then the cell array).


{| class="wikitable"
{| class="wikitable"
Line 54: Line 92:
| 0x00 || Int32 || '''Number of cells''' ('''C''').
| 0x00 || Int32 || '''Number of cells''' ('''C''').
|-
|-
| 0x04 || UInt16['''C'''] || '''Cell indices'''. 0xFFFF if empty.
| 0x04 || UInt16['''C'''] || '''Cell indices'''. Each index is the head index of that cell's chain in the [[#Linked List Array|Linked List Array]]. 0xFFFF if the cell is empty.
|}
|}


Line 62: Line 100:
|-
|-
| 0x00 || Int32[3] || '''Number of cells in the grid's XYZ dimensions'''.
| 0x00 || Int32[3] || '''Number of cells in the grid's XYZ dimensions'''.
|-
|- bgcolor="#AAFFAA"
| 0x0C || Int32[3] || '''Grid bounding box minimum XYZ position'''.
| colspan="3" align="center" | '''If [[#Version List|version]] &ge; 1.18'''
|-
|- bgcolor="#DDFFDD"
| 0x18 || Int32[3] || '''Grid bounding box maximum XYZ position'''.
| 0x0C || Float32[3] || '''Grid bounding box minimum XYZ position'''.
|-
|- bgcolor="#DDFFDD"
| 0x24 || Int32 || {{Unknown-left|'''Unknown'''. Always 0?}}
| 0x18 || Float32[3] || '''Grid bounding box maximum XYZ position'''.
|- bgcolor="#FFAAAA"
| colspan="3" align="center" | '''Else'''
|- bgcolor="#FFDDDD"
| 0x0C || Int32[3] || '''Grid bounding box minimum XYZ position'''. Divide by 4096.
|- bgcolor="#FFDDDD"
| 0x18 || Int32[3] || '''Grid bounding box maximum XYZ position'''. Divide by 4096.
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] == 1.3''' (Cartoon Network Racing only)
|- bgcolor="#DDFFDD"
| 0x24 || Int32 || {{Unknown-left|'''Unknown'''. Always 0.}}
|}
|}


== Linked List Array ==
== Linked List Array ==
After the grid data there's an array of triangle/cell links.
After the grid data there's an array of triangle/cell links. Each cell stores the index of the first entry of its chain, and each entry names a triangle and the index of the next entry in the same chain, ending at 0xFFFF. A triangle is added to every cell it overlaps.


{| class="wikitable"
{| class="wikitable"
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] == 1.18 OR 1.19'''
|- bgcolor="#DDFFDD"
| 0x00 || UInt16 || '''Number of links''' ('''L''').
|- bgcolor="#DDFFDD"
| 0x02 || UInt16[2]['''L'''] || '''Triangle index'''/'''next index'''. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array.
|- bgcolor="#FFAAAA"
| colspan="3" align="center" | '''Else'''
|- bgcolor="#FFDDDD"
| 0x00 || Int32 || '''Number of links''' ('''L''').
| 0x00 || Int32 || '''Number of links''' ('''L''').
|-
|- bgcolor="#FFDDDD"
| 0x04 || UInt16[2]['''L'''] || '''Triangle index''' and '''next index'''. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array (?)
| 0x04 || UInt16[2]['''L'''] || '''Triangle index'''/'''next index'''. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array.
|}
|}


== Custom Attribute Table ==
== Custom Attribute Table ==
This section is only present if '''A''' > 0. It contains a list of '''T''' UInt16s that link each triangle to a [[#Key-Value Property|Key-Value Property]] in a string table. Some tracks contain unused attributes.
This section is only present if '''A''' > 0. Version 1.14 stores a single surface type byte per triangle and has no string table. Not all attributes may be used, as some files have been seen with unused attribute strings.


{| class="wikitable"
{| class="wikitable"
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|- bgcolor="#AAFFAA"
| colspan="3" align="center" | '''If [[#Version List|version]] == 1.14'''
|- bgcolor="#DDFFDD"
| 0x00 || Byte['''T'''] || '''Surface type'''.
|- bgcolor="#FFAAAA"
| colspan="3" align="center" | '''Else'''
|- bgcolor="#FFDDDD"
| 0x00 || UInt16['''T'''] || '''Attribute IDs'''. 0xFFFF if none.
| 0x00 || UInt16['''T'''] || '''Attribute IDs'''. 0xFFFF if none.
|}
|}


=== String Table ===
=== String Table ===
'''Not present in version 1.14.'''
{| class="wikitable"
{| class="wikitable"
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|-
| 0x00 || [[#Key-Value Property|Key-Value Property]]['''A'''] || '''Key-value property strings'''.
| 0x00 || [[#Key-Value Attribute|Key-Value Attribute]]['''A'''] || '''Key-value attribute strings'''.
|}
|}


==== Key-Value Property ====
==== Key-Value Attribute ====
{| class="wikitable"
{| class="wikitable"
! Offset !! Type !! Description
! Offset !! Type !! Description
|-
|-
| 0x00 || UInt16 || '''Key string length''' ('''PK''').
| 0x00 || UInt16 || '''Key string length''' ('''AK''').
|-
|-
| 0x02 || String (Char['''PK''']) || '''Attribute key'''.
| 0x02 || String (Char['''AK''']) || '''Attribute key'''.
|-
|-
| 0x02 + '''K''' || UInt16 || '''Value string length''' ('''PV''').
| 0x02 + '''AK''' || UInt16 || '''Value string length''' ('''AV''').
|-
|-
| 0x04 + '''K''' || String (Char['''PV''']) || '''Attribute value'''. Always ''float(SurfaceType)='''X'''.000000'' in Cartoon Network Racing DS.
| 0x04 + '''AK''' || String (Char['''AV''']) || '''Attribute value'''. Seen as ''float(SurfaceType)='''X'''.000000'' in Cartoon Network Racing DS.
|}
|}


Line 182: Line 246:
|}
|}


= Version List =
= Version List =
= Version List =
{|class="wikitable"
{|class="wikitable"

Latest revision as of 12:30, 11 October 2026

HZC is a collision format used in some Nintendo DS and Nintendo 3DS games developed by Firebrand Games such as Cartoon Network Racing DS and Race Driver: Create & Race.

File Format

The file byte order is always little endian.

Header

The file starts with the following header:

Offset Type Description
0x00 UInt16 Version number. The low byte is the minor version, and the high byte is the major version (always 1).
0x02 UInt16 Number of vertices (V).
0x04 UInt16 Number of triangles (T).
0x06 UInt16 Number of custom attributes (A).
If version ≥ 1.18
0x08 UInt16 Vertex extra count (VE), unknown exact meaning. Usually equal to V or 0.
If version ≥ 1.23
0x0A Byte[10] Unknown.

Vertex Data

Followed by the header, there's plain vertex position data stored as a sequence of groups of 3 values (one per axis). On the DS versions, the values are integers and need to be divided by 4096.

Offset Type Description
If version ≥ 1.18
0x00 Float32[3][V] Vertex XYZ coordinates.
Else
0x00 Int32[3][V] Vertex XYZ coordinates.

Triangle Index Data

After the vertex data, there's a list of T * 3 UInt16s that correspond to the indices of each triangle.

Offset Type Description
0x00 UInt16[3][T] Triangle indices.

Triangle Normal Data

Versions 1.3 and 1.5 only. Directly after the triangle indices there are the triangle's face normals, consisting of 3 Int32s per triangle that divide by 4096. They seem to match the cross product of the triangle's first two edges with a magnitude of 4096.

Offset Type Description
If version == 1.3 OR 1.5
0x00 Int32[3][T] Triangle XYZ normals.

Triangle Adjacency Data

Version 1.5 only. Directly after the triangle normals there is an additional set of 3 UInt16s per triangle. The values appear to be the indices of the three neighboring triangles, with 0xFFFF for open edges.

Offset Type Description
If version == 1.5
0x00 UInt16[3][T] Neighbor triangle indices.

Vertex Extra Data

Versions 1.18 and up only. After the triangle data there is a block of VE x 4 bytes. The purpose is not fully known, but the values are commonly 01 01 01 01 per entry. This block is absent when VE is 0.

Offset Type Description
If version ≥ 1.18
0x00 UInt32[VE] Unknown.

Grid

A spatial grid of 3D cells is used for faster collision detection. Each cell holds an index into the Linked List Array, or 0xFFFF when the cell is empty. The grid is made of three blocks: the cell array, the Grid Info, and the Linked List Array. On versions 1.22 and up the order is reversed (the Linked List Array comes first, then the Grid Info, and then the cell array).

Offset Type Description
0x00 Int32 Number of cells (C).
0x04 UInt16[C] Cell indices. Each index is the head index of that cell's chain in the Linked List Array. 0xFFFF if the cell is empty.

Grid Info

Offset Type Description
0x00 Int32[3] Number of cells in the grid's XYZ dimensions.
If version ≥ 1.18
0x0C Float32[3] Grid bounding box minimum XYZ position.
0x18 Float32[3] Grid bounding box maximum XYZ position.
Else
0x0C Int32[3] Grid bounding box minimum XYZ position. Divide by 4096.
0x18 Int32[3] Grid bounding box maximum XYZ position. Divide by 4096.
If version == 1.3 (Cartoon Network Racing only)
0x24 Int32 Unknown. Always 0.

Linked List Array

After the grid data there's an array of triangle/cell links. Each cell stores the index of the first entry of its chain, and each entry names a triangle and the index of the next entry in the same chain, ending at 0xFFFF. A triangle is added to every cell it overlaps.

Offset Type Description
If version == 1.18 OR 1.19
0x00 UInt16 Number of links (L).
0x02 UInt16[2][L] Triangle index/next index. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array.
Else
0x00 Int32 Number of links (L).
0x04 UInt16[2][L] Triangle index/next index. The next index is 0xFFFF at the end of a cell's chain, otherwise another index into this same array.

Custom Attribute Table

This section is only present if A > 0. Version 1.14 stores a single surface type byte per triangle and has no string table. Not all attributes may be used, as some files have been seen with unused attribute strings.

Offset Type Description
If version == 1.14
0x00 Byte[T] Surface type.
Else
0x00 UInt16[T] Attribute IDs. 0xFFFF if none.

String Table

Not present in version 1.14.

Offset Type Description
0x00 Key-Value Attribute[A] Key-value attribute strings.

Key-Value Attribute

Offset Type Description
0x00 UInt16 Key string length (AK).
0x02 String (Char[AK]) Attribute key.
0x02 + AK UInt16 Value string length (AV).
0x04 + AK String (Char[AV]) Attribute value. Seen as float(SurfaceType)=X.000000 in Cartoon Network Racing DS.
Seen attributes (Cartoon Network Racing DS)
Key Value Found in
COL_grass float(SurfaceType)=1.000000
  • CrossTown.hzc
  • evilGlade.hzc
  • IslandDash.hzc
grass float(SurfaceType)=1.000000 Townsville.hzc
Grass float(SurfaceType)=1.000000
  • AronSpeed.hzc
  • MandarkLab.hzc
  • MidNowhere.hzc
heavyTerrain float(SurfaceType)=2.000000
  • CrossTown.hzc
  • MandarkLab.hzc
  • SnowSunday.hzc
HeavyTerrain float(SurfaceType)=3.000000
  • IslandDash.hzc
  • MandarkLab.hzc
MudPuddle float(SurfaceType)=5.000000 IslandDash.hzc
not_track
  • float(SurfaceType)=1.000000
  • float(SurfaceType)=4.000000
  • MandarkLab.hzc
  • MidNowhere.hzc
  • Townsville.hzc
raceTrackFloor — DextersLab.hzc
raceTrackWalls — DextersLab.hzc
RoughGround
  • float(SurfaceType)=0.000000
  • float(SurfaceType)=4.000000
  • AronSpeed.hzc
  • MandarkLab.hzc
  • MidNowhere.hzc
terrainLight float(SurfaceType)=0.000000
  • MandarkLab.hzc
  • MountRush.hzc

Version List

Version Found in
1.3
1.4 Race Driver: Create & Race
1.5
1.12
1.14 TrackMania Turbo (2010)
1.18
1.19 Need for Speed: The Run 3DS
1.22 Fast & Furious: Showdown 3DS
1.23

Tools

The following tools can handle HZC files:

  • (none)