Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

3DC Animated Model File Format

Animated variant of the 3D model format. The fixed header is shared with 3D models; animation directories depend on the renderer generation.

Differences from .3D

Aspect.3D.3DC
Frames0 in software static files, 1 in Glide static filesMultiple animation frames, or a single static frame
frame_type (frame 0)02, 4, or 8
Animated frame dataNoneFrames 1+ with compressed or full-precision geometry
Section4 (SubObject BVH)Present in v5.0Absent in Glide animations; software uses a different auxiliary layout
Vertex-normal indirection tablePresentAlways absent (offset=0)
Versionv4.0 or v5.0v4.0 (fxart/), v2.6 or v2.7 (3dart/)

All shared structures (header, face data, vertex coordinates, face normals, vertex normals, texture encoding) are documented in 3D.md.

Glide animation frame data

The frame data array at offset_frame_data contains num_frames × 16-byte records (see 3D.md — Frame Data for the record layout).

Frame 0 always points to the base geometry (same as .3D files). Frames 1+ contain encoded vertex data and face normals. Compressed vertices are deltas from frame zero, not absolute positions.

frame_type Values

ValueMeaningFrame 1+ vertex encodingFrame 1+ normal encoding
2Compressed animationi16 × 3 (6 bytes/vertex)10-10-10-2 packed (4 bytes/face)
4Full-precision animationi32 × 3 (12 bytes/vertex)10-10-10-2 packed (4 bytes/face)
8Static (single-frame .3DC)N/AN/A

frame_type is only meaningful in frame 0’s record. Frame 1+ records always have frame_type = 0.

Compressed vertex reconstruction

The low four bits of frame zero’s type select the vertex encoding. For type 2, each later signed i16 component is subtracted from the corresponding decoded frame-zero component. When type flag 0x10 is clear, divide the signed delta by 256 before subtraction. When it is set, subtract the signed delta in whole model units. Store the resulting absolute coordinate at single precision. Each frame uses frame zero as its base; deltas are not accumulated between frames.

Type 1 uses signed byte deltas subtracted in whole model units. Type 4 stores absolute signed i32 components scaled by 1/256. Frame zero itself uses decoded base geometry regardless of the later-frame encoding.

10-10-10-2 Packed Normal Format

Used for face normals in frames 1+:

Bits  0- 9: nx (10-bit signed, subtract 1024 if >= 512)
Bits 10-19: ny (10-bit signed, subtract 1024 if >= 512)
Bits 20-29: nz (10-bit signed, subtract 1024 if >= 512)
Bits 30-31: unused (values: 0 and 3)

Each component is divided by 256.0 to produce the final normal vector.

The engine’s normal decoder extracts the three 10-bit signed components via sign-extending shifts and discards bits 30–31:

nx = (float)((packed << 22) >> 22) * scale;   // bits  0–9, sign-extended
ny = (float)((packed << 12) >> 22) * scale;   // bits 10–19, sign-extended
nz = (float)((packed <<  2) >> 22) * scale;   // bits 20–29, sign-extended
// bits 30–31 are shifted out by << 2 — never read

The values are 0 and 3. Parsers should mask or discard these bits.

Section Layout (v4.0)

Same as 3D.md — Section Layout, but with animated frame data inserted and .3D-only sections absent:

  1. Face Data — at 0x40
  2. Vertex Coordinates — base frame positions
  3. Face Normals — base frame normals
  4. Frame Data — num_frames × 16-byte records
  5. Animated Frame Vertex/Normal Data — frames 1+ geometry
  6. Vertex Normals — per-vertex normals (f32 × 3)

Software animation directory

In v2.6/v2.7, offset_frame_data points to a 24-byte animation header. It is not the first frame record. Values are little-endian.

OffsetSizeTypeNameDescription
0x004u32table_offsetAbsolute file offset of the frame directory
0x044u32face_data_sizeByte length of shared face records
0x084u32unknown_08Auxiliary field
0x0C2u16flagsBit 0 selects compressed frame data
0x0E2u16reference_frameFrame with full i32 positions when compressed
0x104u32unknown_10Auxiliary field
0x142u16unknown_14Auxiliary field
0x161u8unknown_16Auxiliary field
0x171u8delta_shiftShift applied to compressed position deltas

The directory contains num_frames records. Compressed records occupy 12 bytes; uncompressed records occupy 16 bytes.

OffsetSizeTypeNameDescription
0x004u32vertex_offsetAbsolute file offset of frame positions or deltas
0x044u32normal_offsetAbsolute file offset of face normals
0x084u32auxiliary_offsetAbsolute file offset of per-face auxiliary data
0x0C4u32unknown_0cPresent only in uncompressed records

Uncompressed positions and face normals contain three signed i32 components, each scaled by 1/256.

In compressed animations, the reference frame contains full signed i32 positions. Other frames contain three signed i16 deltas per vertex. Reconstruct each raw component with wrapping i32 arithmetic:

position = reference_position + (signed_delta << (delta_shift & 31))

Divide the reconstructed raw component by 256. Every frame uses the same reference frame. Deltas are added, not subtracted or accumulated from the preceding frame. Frame zero may itself be compressed.

Every compressed frame’s face normals use signed 10-bit components in this order:

Bits 20-29: x
Bits 10-19: y
Bits  0- 9: z
Bits 30-31: discarded

Sign-extend each component and divide it by 256. This component order differs from Glide’s packed normals. Use decoded frame-zero positions and normals as the model’s base geometry.

External References