Module mdl

Module mdl 

Source
Expand description

MDL binary model support. MDL binary model reader and writer.

MDL is the 3D model format used by the Odyssey engine (KotOR/KotOR2). Each model consists of two files: an MDL file containing the node tree, controllers, and metadata, and a companion MDX file containing interleaved per-vertex attribute data.

The binary variant uses a 12-byte wrapper followed by a memory-mapped content blob. All internal offsets are content-relative (byte 0 = wrapper end = on-disk byte 12).

§File Layout

MDL file:                             MDX file:
+------------------------------+      +------------------------------+
| Wrapper (12 bytes)           |      | Mesh 1 vertex data           |
| - zero_marker (u32)          |      | (stride * vertex_count bytes)|
| - mdl_content_size (u32)     |      | + terminator (1 stride row)  |
| - mdx_file_size (u32)        |      +- - - - - - - - - - - - - - -+
+------------------------------+      | padding to 16-byte boundary  |
| Geometry Header (80 bytes)   |      +------------------------------+
| Model Header (116 bytes)     |      | Mesh 2 vertex data           |
+------------------------------+      | + terminator                 |
| Name Offset Array (u32[])    |      +- - - - - - - - - - - - - - -+
| Name Strings (null-term)     |      | ...                          |
+------------------------------+      +------------------------------+
| Animation Header Array       |      | Last mesh vertex data        |
| (136 bytes * anim_count)     |      | + terminator (no final pad)  |
+------------------------------+      +------------------------------+
| Node Tree (recursive DFS)    |
| - Node header (80 bytes)     |
| - Type-specific extra data   |
| - Controller keys + data     |
| - Children (recurse)         |
+------------------------------+
| Animation Node Trees         |
| (one tree per animation)     |
+------------------------------+

§Wrapper (12 bytes)

0x00..0x04  zero_marker      (u32, always 0)
0x04..0x08  mdl_content_size (u32, bytes after wrapper)
0x08..0x0C  mdx_file_size    (u32, companion MDX total size)

§Geometry Header (80 bytes, content +0x00..+0x4F)

0x00..0x04  fn_ptr1          (u32, leaked toolset vtable pointer)
0x04..0x08  fn_ptr2          (u32, leaked toolset vtable pointer)
0x08..0x28  model_name       (char[32], null-terminated)
0x28..0x2C  root_node_ptr    (u32, content-relative)
0x2C..0x30  node_count       (u32)
0x30..0x3C  runtime_arr1     (12 bytes, zeros on disk)
0x3C..0x48  runtime_arr2     (12 bytes, zeros on disk)
0x48..0x4C  ref_count        (u32, zero on disk)
0x4C..0x4D  model_type       (u8, always 2 for geometry)
0x4D..0x50  padding          (3 bytes)

§Model Header (116 bytes, content +0x50..+0xC3)

0x50        classification   (u8: 0=Other, 1=Effect, 2=Tile, 4=Character, 8=Door)
0x51        subclassification (u8)
0x52        unknown_52       (u8, always 0 in vanilla)
0x53        affected_by_fog  (u8, 0 or 1)
0x54..0x58  num_child_models (u32, always 0 in vanilla K1)
0x58..0x64  animation_arr    (CExoArrayList: ptr/count/alloc)
0x64..0x68  supermodel_ref   (u32, always 0 in vanilla K1)
0x68..0x74  bounding_min     (3x f32)
0x74..0x80  bounding_max     (3x f32)
0x80..0x84  radius           (f32, bounding sphere)
0x84..0x88  animation_scale  (f32, default 1.0)
0x88..0xA8  supermodel_name  (char[32], null-terminated)
0xA8..0xAC  off_anim_root    (u32, content-relative; usually = root_node_ptr)
0xAC..0xB0  padding          (4 bytes)
0xB0..0xB4  mdx_size         (u32, total MDX data size)
0xB4..0xB8  mdx_offset       (u32, always 0 in vanilla K1)
0xB8..0xBC  name_offsets_ptr (u32, content-relative -> u32[] name pointers)
0xBC..0xC0  name_count       (u32)

§Node Header (80 bytes)

0x00..0x02  type_flags       (u16, bitfield: see node_flags module)
0x02..0x04  node_number      (u16, name_index for geometry / anim mapping for anims)
0x04..0x06  name_index       (u16, index into name table)
0x06..0x08  padding          (u16)
0x08..0x0C  off_root         (u32, always 0 in vanilla)
0x0C..0x10  off_parent       (u32, content-relative pointer to parent)
0x10..0x1C  position         (3x f32: x, y, z)
0x1C..0x2C  orientation      (4x f32: w, x, y, z quaternion)
0x2C..0x38  children_arr     (CExoArrayList: ptr/count/alloc)
0x38..0x44  ctrl_key_arr     (CExoArrayList: ptr/count/alloc)
0x44..0x50  ctrl_data_arr    (CExoArrayList: ptr/count/alloc)

§TriMesh Extra Header (332 bytes, node +0x50..+0x19B)

+0x00..+0x08  fn_ptr stubs       (2x u32, leaked toolset pointers)
+0x08..+0x14  face_arr           (CExoArrayList -> MaxFace[32B] array)
+0x14..+0x54  bounding/color     (bbox, bsphere, diffuse, ambient, transparency)
+0x58..+0x98  texture names      (texture_0[32], texture_1[32])
+0x98..+0xD4  CExoArrayList[5]   (index buffer submission system)
+0xD4..+0xE8  shared index data  (offset, pool, size, indices_per_face, padding)
+0xE8..+0xFC  UV animation       (animate_uv, direction, jitter, speed)
+0xFC..+0x100 vertex_stride      (u32, bytes per MDX vertex)
+0x100..+0x130 MDX layout        (flags + 12 attribute byte offsets)
+0x130..+0x140 mesh properties   (vertex_count, channel_count, flags)
+0x13C..+0x144 total_surface_area (f32)
+0x144..+0x148 mdx_data_offset   (u32, byte offset into MDX file)
+0x148..+0x14C vert_array_offset (u32, content-relative -> position data)

§Animation Header (136 bytes)

0x00..0x08  fn_ptrs          (2x u32, leaked toolset pointers)
0x08..0x28  name             (char[32], null-terminated)
0x28..0x2C  root_node_ptr    (u32, content-relative)
0x2C..0x30  node_count       (u32)
0x30..0x48  runtime arrays   (24 bytes, zeros on disk)
0x48..0x4C  ref_count        (u32, zero on disk)
0x4C..0x50  model_type+pad   (u8=5 + 3 bytes padding)
0x50..0x54  length           (f32, duration in seconds)
0x54..0x58  transition       (f32, blend time in seconds)
0x58..0x78  anim_root        (char[32], geometry node name)
0x78..0x84  event_arr        (CExoArrayList: ptr/count/alloc)
0x84..0x88  padding          (4 bytes)

Binary format offsets verified against swkotor.exe via Ghidra decompilation. See docs/notes/mdl_mdx.md for full details.

Re-exports§

pub use ascii_reader::read_mdl_ascii;
pub use ascii_reader::read_mdl_ascii_from_str;
pub use ascii_writer::write_mdl_ascii;
pub use ascii_writer::write_mdl_ascii_to_string;
pub use ascii_writer::MdlAsciiError;
pub use controllers::MdlController;
pub use controllers::MdlControllerType;
pub use controllers::MdlKey;
pub use reader::read_mdl;
pub use reader::read_mdl_from_bytes;
pub use types::AabbNode;
pub use types::MdlAabb;
pub use types::MdlAnimMesh;
pub use types::MdlCamera;
pub use types::MdlDangly;
pub use types::MdlEmitter;
pub use types::MdlFace;
pub use types::MdlLight;
pub use types::MdlMesh;
pub use types::MdlNodeData;
pub use types::MdlReference;
pub use types::MdlSaber;
pub use types::MdlSkin;
pub use writer::write_mdl;
pub use writer::write_mdl_to_vec;
pub use writer::write_mdl_with_mdx_to_vec;

Modules§

ascii_names
ASCII name registry for controllers, classifications, and node types. ASCII MDL name registry for controllers, classifications, and node types.
ascii_reader
ASCII MDL reader. ASCII MDL reader.
ascii_writer
ASCII MDL writer. ASCII MDL writer.
controllers
MDL controller types and keyframe structures. MDL controller types and keyframe structures.
node_flags
Bitflags for node type identification in the on-disk binary format.
orientation
Quaternion and axis-angle conversion utilities. Quaternion and axis-angle conversion utilities for MDL orientation data.
reader
MDL binary reader. MDL binary reader.
types
Node-specific data types. Node-specific data types for the MDL format.
writer
MDL binary writer. MDL binary writer.

Structs§

Mdl
The high-level MDL container.
MdlAnimEvent
An event that fires at a specific time during an animation.
MdlAnimNode
A node in an animation’s node tree.
MdlAnimation
A named animation sequence.
MdlNode
A node in the MDL hierarchy.
MdlWriteResult
Result of writing an MDL model with its companion MDX vertex data.

Enums§

MdlError
MDL binary parsing error type.

Functions§

assign_inverted_counters
Assign inverted counter values to all mesh nodes in DFS tree order.