rakata_formats/mdl/
controllers.rs

1//! MDL controller types and keyframe structures.
2
3/// Controller type code identifying which property is animated.
4///
5/// Stored as a raw `u32` matching the on-disk binary format. Named constants
6/// are provided for Ghidra-verified types; unknown codes are preserved
7/// losslessly for roundtrip fidelity.
8///
9/// Controller type codes are node-type-specific - the same numeric value may
10/// have different semantic meaning on different node types (e.g., Light vs
11/// Emitter). The base node types (Position, Orientation, Scale) are shared
12/// across all node types.
13///
14/// Base node controller codes verified via `MdlNode::InternalParseField`
15/// (`0x00465560`). See `docs/notes/mdl_mdx.md` §Model Formats.
16#[derive(Clone, Copy, PartialEq, Eq, Hash)]
17pub struct MdlControllerType(u32);
18
19impl MdlControllerType {
20    // --- Base node controllers (all node types) ---
21    // Verified via `MdlNode::InternalParseField` (`0x00465560`).
22
23    /// Position (3 floats: x, y, z). Code 8.
24    pub const POSITION: Self = Self(8);
25    /// Orientation quaternion (4 floats: w, x, y, z). Code 20.
26    pub const ORIENTATION: Self = Self(20);
27    /// Uniform scale (1 float). Code 36.
28    pub const SCALE: Self = Self(36);
29
30    // --- Mesh node controllers (trimesh, skin, dangly, aabb, saber, animmesh) ---
31    // Verified via `MdlNodeTriMesh::InternalParseField` (`0x004658b0`).
32
33    /// Self-illumination color (3 floats: r, g, b). Code 100. Mesh context.
34    pub const SELFILLUMCOLOR: Self = Self(100);
35    /// Alpha transparency (1 float). Code 132. Mesh context.
36    pub const ALPHA: Self = Self(132);
37
38    // --- Light node controllers ---
39    // Verified via `MdlNodeLight::InternalParseField` (`0x00469150`).
40
41    /// Light color (3 floats: r, g, b). Code 76. Light context.
42    pub const COLOR: Self = Self(76);
43    /// Light radius (1 float). Code 88. Light context.
44    pub const RADIUS: Self = Self(88);
45    /// Shadow radius (1 float). Code 96. Light context.
46    pub const SHADOW_RADIUS: Self = Self(96);
47    /// Vertical displacement (1 float). Code 100. Light context.
48    ///
49    /// Note: same raw code as `SELFILLUMCOLOR` (mesh) and `DRAG` (emitter).
50    pub const VERTICAL_DISPLACEMENT: Self = Self(100);
51    /// Light multiplier (1 float). Code 140. Light context.
52    pub const MULTIPLIER: Self = Self(140);
53
54    // --- Emitter node controllers ---
55    // Codes from mdledit MDL.h; to be independently verified via Ghidra
56    // `MdlNodeEmitter::InternalParseField` (`0x00469700`).
57
58    /// Emitter alpha end (1 float). Code 80.
59    pub const ALPHA_END: Self = Self(80);
60    /// Emitter alpha start (1 float). Code 84.
61    pub const ALPHA_START: Self = Self(84);
62    /// Emitter birthrate (1 float). Code 88.
63    pub const BIRTHRATE: Self = Self(88);
64    /// Emitter bounce coefficient (1 float). Code 92.
65    pub const BOUNCE_CO: Self = Self(92);
66    /// Emitter combine time (1 float). Code 96.
67    pub const COMBINETIME: Self = Self(96);
68    /// Emitter drag (1 float). Code 100.
69    pub const DRAG: Self = Self(100);
70    /// Emitter frames per second (1 float). Code 104.
71    pub const FPS: Self = Self(104);
72    /// Emitter frame end (1 float). Code 108.
73    pub const FRAME_END: Self = Self(108);
74    /// Emitter frame start (1 float). Code 112.
75    pub const FRAME_START: Self = Self(112);
76    /// Emitter gravity (1 float). Code 116.
77    pub const GRAV: Self = Self(116);
78    /// Emitter life expectancy (1 float). Code 120.
79    pub const LIFE_EXP: Self = Self(120);
80    /// Emitter mass (1 float). Code 124.
81    pub const MASS: Self = Self(124);
82    /// Emitter point-to-point bezier control 2 (1 float). Code 128.
83    pub const P2P_BEZIER2: Self = Self(128);
84    /// Emitter point-to-point bezier control 3 (1 float). Code 132.
85    pub const P2P_BEZIER3: Self = Self(132);
86    /// Emitter particle rotation (1 float). Code 136.
87    pub const PARTICLE_ROT: Self = Self(136);
88    /// Emitter random velocity (1 float). Code 140.
89    pub const RANDVEL: Self = Self(140);
90    /// Emitter size start (1 float). Code 144.
91    pub const SIZE_START: Self = Self(144);
92    /// Emitter size end (1 float). Code 148.
93    pub const SIZE_END: Self = Self(148);
94    /// Emitter size start Y (1 float). Code 152.
95    pub const SIZE_START_Y: Self = Self(152);
96    /// Emitter size end Y (1 float). Code 156.
97    pub const SIZE_END_Y: Self = Self(156);
98    /// Emitter spread (1 float). Code 160.
99    pub const SPREAD: Self = Self(160);
100    /// Emitter threshold (1 float). Code 164.
101    pub const THRESHOLD: Self = Self(164);
102    /// Emitter velocity (1 float). Code 168.
103    pub const VELOCITY: Self = Self(168);
104    /// Emitter X size (1 float). Code 172.
105    pub const XSIZE: Self = Self(172);
106    /// Emitter Y size (1 float). Code 176.
107    pub const YSIZE: Self = Self(176);
108    /// Emitter blur length (1 float). Code 180.
109    pub const BLUR_LENGTH: Self = Self(180);
110    /// Emitter lightning delay (1 float). Code 184.
111    pub const LIGHTNING_DELAY: Self = Self(184);
112    /// Emitter lightning radius (1 float). Code 188.
113    pub const LIGHTNING_RADIUS: Self = Self(188);
114    /// Emitter lightning scale (1 float). Code 192.
115    pub const LIGHTNING_SCALE: Self = Self(192);
116    /// Emitter lightning subdivision (1 float). Code 196.
117    pub const LIGHTNING_SUB_DIV: Self = Self(196);
118    /// Emitter lightning zigzag (1 float). Code 200.
119    pub const LIGHTNING_ZIGZAG: Self = Self(200);
120    /// Emitter alpha mid (1 float). Code 216.
121    pub const ALPHA_MID: Self = Self(216);
122    /// Emitter percent start (1 float). Code 220.
123    pub const PERCENT_START: Self = Self(220);
124    /// Emitter percent mid (1 float). Code 224.
125    pub const PERCENT_MID: Self = Self(224);
126    /// Emitter percent end (1 float). Code 228.
127    pub const PERCENT_END: Self = Self(228);
128    /// Emitter size mid (1 float). Code 232.
129    pub const SIZE_MID: Self = Self(232);
130    /// Emitter size mid Y (1 float). Code 236.
131    pub const SIZE_MID_Y: Self = Self(236);
132    /// Emitter random birthrate (1 float). Code 240.
133    pub const RANDOM_BIRTH_RATE: Self = Self(240);
134    /// Emitter target size (1 float). Code 252.
135    pub const TARGET_SIZE: Self = Self(252);
136    /// Emitter number of control points (1 float). Code 256.
137    pub const NUM_CONTROL_PTS: Self = Self(256);
138    /// Emitter control point radius (1 float). Code 260.
139    pub const CONTROL_PT_RADIUS: Self = Self(260);
140    /// Emitter control point delay (1 float). Code 264.
141    pub const CONTROL_PT_DELAY: Self = Self(264);
142    /// Emitter tangent spread (1 float). Code 268.
143    pub const TANGENT_SPREAD: Self = Self(268);
144    /// Emitter tangent length (1 float). Code 272.
145    pub const TANGENT_LENGTH: Self = Self(272);
146    /// Emitter color mid (3 floats: r, g, b). Code 284.
147    pub const COLOR_MID: Self = Self(284);
148    /// Emitter color end (3 floats: r, g, b). Code 380.
149    pub const COLOR_END: Self = Self(380);
150    /// Emitter color start (3 floats: r, g, b). Code 392.
151    pub const COLOR_START: Self = Self(392);
152    /// Emitter detonate (1 float). Code 502.
153    pub const DETONATE: Self = Self(502);
154
155    /// Creates a controller type from a raw type code.
156    pub const fn from_raw(code: u32) -> Self {
157        Self(code)
158    }
159
160    /// Returns the raw type code.
161    #[must_use = "raw returns a computed value and has no side effects"]
162    pub const fn raw(self) -> u32 {
163        self.0
164    }
165}
166
167impl std::fmt::Debug for MdlControllerType {
168    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169        match *self {
170            Self::POSITION => write!(f, "Position({})", self.0),
171            Self::ORIENTATION => write!(f, "Orientation({})", self.0),
172            Self::SCALE => write!(f, "Scale({})", self.0),
173            _ => write!(f, "Unknown({})", self.0),
174        }
175    }
176}
177
178impl std::fmt::Display for MdlControllerType {
179    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180        match *self {
181            Self::POSITION => f.write_str("Position"),
182            Self::ORIENTATION => f.write_str("Orientation"),
183            Self::SCALE => f.write_str("Scale"),
184            _ => write!(f, "Unknown({})", self.0),
185        }
186    }
187}
188
189impl From<u32> for MdlControllerType {
190    fn from(code: u32) -> Self {
191        Self(code)
192    }
193}
194
195impl From<MdlControllerType> for u32 {
196    fn from(ct: MdlControllerType) -> u32 {
197        ct.0
198    }
199}
200
201/// Bezier flag bit in the raw column_count byte (bit 4).
202///
203/// When set, the actual value count per keyframe row is
204/// `(raw_column_count & 0x0F) * 3` (control point triplets).
205pub const CTRL_FLAG_BEZIER: u8 = 0x10;
206
207/// A controller definition for a node.
208///
209/// Defines a set of animation keys that drive one property over time.
210///
211/// The binary `NewController` header is 16 bytes. Bytes +0x04..+0x05 and
212/// +0x0D..+0x0F are preserved verbatim for roundtrip fidelity.
213#[derive(Debug, Clone, PartialEq)]
214pub struct MdlController {
215    /// The type of property being controlled (Position, Orientation, etc.).
216    pub controller_type: MdlControllerType,
217    /// The animation keys (time + values).
218    pub keys: Vec<MdlKey>,
219    /// Raw column_count byte from controller key header +0x0C.
220    ///
221    /// The lower 4 bits encode the base column count. Bit 4 (0x10) is the
222    /// Bezier flag -- when set, each row has 3x the base columns (control
223    /// point triplets). Special case: ORIENTATION with raw value 2 means
224    /// integral compressed quaternion (1 u32 per row, stored as f32 bits).
225    ///
226    /// Preserved for roundtrip fidelity; the reader decodes this to
227    /// determine the actual value count per keyframe row.
228    pub raw_column_count: u8,
229    /// Unknown bytes from controller key header +0x04..+0x05.
230    ///
231    /// Preserved verbatim for roundtrip fidelity per the reserved field rule.
232    /// Zero for newly constructed controllers.
233    pub key_unknown_04: [u8; 2],
234    /// Unknown bytes from controller key header +0x0D..+0x0F.
235    ///
236    /// Preserved verbatim for roundtrip fidelity per the reserved field rule.
237    /// Zero for newly constructed controllers.
238    pub key_unknown_0d: [u8; 3],
239}
240
241/// A single animation keyframe.
242#[derive(Debug, Clone, PartialEq)]
243pub struct MdlKey {
244    /// Time of the keyframe.
245    pub time: f32,
246    /// Values associated with this key (e.g., [x, y, z] for Position).
247    pub values: Vec<f32>,
248}