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}