1use serde::{Deserialize, Serialize};
2
3use crate::error::ImportError;
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
6#[serde(rename_all = "camelCase")]
7pub struct NmdParsedManifest {
8 #[serde(default = "default_nmd_format", skip_deserializing)]
9 pub format: &'static str,
10 pub byte_length: usize,
11 pub metadata: NmdParsedMetadata,
12 pub global_track_count: usize,
13 pub keyframe_bundles: NmdKeyframeBundleCounts,
14 pub payload: NmdPayloadSummary,
15 pub diagnostics: Vec<NmdDiagnostic>,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct NmdParsedMetadata {
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub main_object_name: Option<String>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub preferred_fps: Option<f32>,
25 pub annotation_count: usize,
26}
27
28#[derive(Debug, Clone, Default, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct NmdKeyframeBundleCounts {
31 pub accessory: usize,
32 pub bone: usize,
33 pub camera: usize,
34 pub light: usize,
35 pub model: usize,
36 pub morph: usize,
37 pub self_shadow: usize,
38 pub unknown: usize,
39}
40
41#[derive(Debug, Clone, Default, Serialize, Deserialize)]
42#[serde(rename_all = "camelCase")]
43pub struct NmdPayloadSummary {
44 pub accessory_keyframes: usize,
45 pub bone_local_tracks: usize,
46 pub bone_keyframes: usize,
47 pub morph_local_tracks: usize,
48 pub morph_keyframes: usize,
49 pub camera_keyframes: usize,
50 pub light_keyframes: usize,
51 pub model_keyframes: usize,
52 pub self_shadow_keyframes: usize,
53 pub accessory_frames: Vec<NmdAccessoryKeyframe>,
54 pub bone_frames: Vec<NmdBoneKeyframe>,
55 pub morph_frames: Vec<NmdMorphKeyframe>,
56 pub camera_frames: Vec<NmdCameraKeyframe>,
57 pub light_frames: Vec<NmdLightKeyframe>,
58 pub model_frames: Vec<NmdModelKeyframe>,
59 pub self_shadow_frames: Vec<NmdSelfShadowKeyframe>,
60}
61
62#[derive(Debug, Clone, Default, Serialize, Deserialize)]
63#[serde(rename_all = "camelCase")]
64pub struct NmdAccessoryKeyframe {
65 pub common: NmdKeyframeCommon,
66 pub track_index: u64,
67 pub translation: [f32; 3],
68 pub orientation: [f32; 4],
69 pub scale_factor: f32,
70 pub opacity: f32,
71 pub effect_parameters: Vec<NmdEffectParameter>,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub binding: Option<NmdModelBinding>,
74 #[serde(skip_serializing_if = "Option::is_none")]
75 pub visible: Option<bool>,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub shadow_enabled: Option<bool>,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub add_blending_enabled: Option<bool>,
80}
81
82#[derive(Debug, Clone, Default, Serialize, Deserialize)]
83#[serde(rename_all = "camelCase")]
84pub struct NmdKeyframeCommon {
85 pub frame_index: u64,
86 #[serde(skip_serializing_if = "Option::is_none")]
87 pub layer_index: Option<u32>,
88 #[serde(skip_serializing_if = "Option::is_none")]
89 pub selected: Option<bool>,
90}
91
92#[derive(Debug, Clone, Default, Serialize, Deserialize)]
93#[serde(rename_all = "camelCase")]
94pub struct NmdBoneKeyframe {
95 pub common: NmdKeyframeCommon,
96 pub track_index: u64,
97 pub local_translation: [f32; 3],
98 pub local_orientation: [f32; 4],
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub interpolation: Option<NmdBoneKeyframeInterpolation>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub stage_index: Option<u32>,
103 #[serde(skip_serializing_if = "Option::is_none")]
104 pub physics_simulation_enabled: Option<bool>,
105}
106
107#[derive(Debug, Clone, Default, Serialize, Deserialize)]
108#[serde(rename_all = "camelCase")]
109pub struct NmdBoneKeyframeInterpolation {
110 #[serde(skip_serializing_if = "Option::is_none")]
111 pub x: Option<NmdInterpolationUnit>,
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub y: Option<NmdInterpolationUnit>,
114 #[serde(skip_serializing_if = "Option::is_none")]
115 pub z: Option<NmdInterpolationUnit>,
116 #[serde(skip_serializing_if = "Option::is_none")]
117 pub orientation: Option<NmdInterpolationUnit>,
118}
119
120#[derive(Debug, Clone, Default, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct NmdMorphKeyframe {
123 pub common: NmdKeyframeCommon,
124 pub track_index: u64,
125 pub weight: f32,
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub interpolation: Option<NmdInterpolationUnit>,
128}
129
130#[derive(Debug, Clone, Default, Serialize, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct NmdCameraKeyframe {
133 pub common: NmdKeyframeCommon,
134 pub look_at: [f32; 3],
135 pub angle: [f32; 3],
136 pub fov: f32,
137 pub distance: f32,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub interpolation: Option<NmdCameraKeyframeInterpolation>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub stage_index: Option<u32>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub perspective_view_enabled: Option<bool>,
144}
145
146#[derive(Debug, Clone, Default, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct NmdCameraKeyframeInterpolation {
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub x: Option<NmdInterpolationUnit>,
151 #[serde(skip_serializing_if = "Option::is_none")]
152 pub y: Option<NmdInterpolationUnit>,
153 #[serde(skip_serializing_if = "Option::is_none")]
154 pub z: Option<NmdInterpolationUnit>,
155 #[serde(skip_serializing_if = "Option::is_none")]
156 pub angle: Option<NmdInterpolationUnit>,
157 #[serde(skip_serializing_if = "Option::is_none")]
158 pub fov: Option<NmdInterpolationUnit>,
159 #[serde(skip_serializing_if = "Option::is_none")]
160 pub distance: Option<NmdInterpolationUnit>,
161}
162
163#[derive(Debug, Clone, Default, Serialize, Deserialize)]
164#[serde(rename_all = "camelCase")]
165pub struct NmdLightKeyframe {
166 pub common: NmdKeyframeCommon,
167 pub color: [f32; 3],
168 pub direction: [f32; 3],
169}
170
171#[derive(Debug, Clone, Default, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct NmdModelKeyframe {
174 pub common: NmdKeyframeCommon,
175 pub visible: bool,
176 pub constraint_state_count: usize,
177 pub effect_parameter_count: usize,
178 pub binding_count: usize,
179 pub constraint_states: Vec<NmdConstraintState>,
180 pub effect_parameters: Vec<NmdEffectParameter>,
181 pub bindings: Vec<NmdModelBinding>,
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub edge: Option<NmdEdge>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub add_blending_enabled: Option<bool>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub physics_simulation_enabled: Option<bool>,
188}
189
190#[derive(Debug, Clone, Default, Serialize, Deserialize)]
191#[serde(rename_all = "camelCase")]
192pub struct NmdConstraintState {
193 pub track_index: u64,
194 pub enabled: bool,
195}
196
197#[derive(Debug, Clone, Default, Serialize, Deserialize)]
198#[serde(rename_all = "camelCase")]
199pub struct NmdEffectParameter {
200 pub track_index: u64,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub bool_value: Option<bool>,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub int_value: Option<i32>,
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub float_value: Option<f32>,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub vector_value: Option<[f32; 4]>,
209}
210
211#[derive(Debug, Clone, Default, Serialize, Deserialize)]
212#[serde(rename_all = "camelCase")]
213pub struct NmdModelBinding {
214 #[serde(skip_serializing_if = "Option::is_none")]
215 pub local_bone_track_index: Option<u64>,
216 pub global_object_track_index: u64,
217 pub global_bone_track_index: u64,
218}
219
220#[derive(Debug, Clone, Default, Serialize, Deserialize)]
221#[serde(rename_all = "camelCase")]
222pub struct NmdEdge {
223 pub color: [f32; 4],
224 pub scale_factor: f32,
225}
226
227#[derive(Debug, Clone, Default, Serialize, Deserialize)]
228#[serde(rename_all = "camelCase")]
229pub struct NmdSelfShadowKeyframe {
230 pub common: NmdKeyframeCommon,
231 pub enabled: bool,
232 pub mode: i32,
233 pub distance: f32,
234}
235
236#[derive(Debug, Clone, Default, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct NmdInterpolationUnit {
239 #[serde(skip_serializing_if = "Option::is_none")]
240 pub integer: Option<[u32; 4]>,
241 #[serde(skip_serializing_if = "Option::is_none")]
242 pub float: Option<[f32; 4]>,
243}
244
245#[derive(Debug, Clone, Serialize, Deserialize)]
246#[serde(rename_all = "camelCase")]
247pub struct NmdDiagnostic {
248 pub level: String,
249 pub code: String,
250 pub message: String,
251}
252
253pub fn parse_nmd_manifest(data: &[u8]) -> Result<NmdParsedManifest, ImportError> {
254 if data.is_empty() {
255 return Err(ImportError::UnexpectedEof(1));
256 }
257
258 let mut r = ProtoReader { data, pos: 0 };
259 let mut metadata = NmdParsedMetadata {
260 main_object_name: None,
261 preferred_fps: None,
262 annotation_count: 0,
263 };
264 let mut global_track_count = 0usize;
265 let mut keyframe_bundles = NmdKeyframeBundleCounts::default();
266 let mut payload = NmdPayloadSummary::default();
267
268 while !r.is_eof() {
269 let Some((field, wire_type)) = r.read_key()? else {
270 break;
271 };
272 match (field, wire_type) {
273 (1, WIRE_LEN) => {
274 r.skip_len()?;
275 metadata.annotation_count += 1;
276 }
277 (2, WIRE_LEN) => {
278 let bytes = r.read_len()?;
279 metadata.main_object_name = Some(String::from_utf8_lossy(bytes).into_owned());
280 }
281 (3, WIRE_FIXED32) => {
282 let preferred_fps = r.read_f32()?;
283 if !preferred_fps.is_finite() {
284 return Err(ImportError::UnsupportedFormat {
285 format: "NMD",
286 detail: "preferred FPS is not finite",
287 });
288 }
289 metadata.preferred_fps = Some(preferred_fps);
290 }
291 (4, WIRE_LEN) => {
292 r.skip_len()?;
293 global_track_count += 1;
294 }
295 (5, WIRE_LEN) => {
296 let bytes = r.read_len()?;
297 count_keyframe_bundle(bytes, &mut keyframe_bundles, &mut payload)?;
298 }
299 _ => r.skip_value(wire_type)?,
300 }
301 }
302
303 Ok(NmdParsedManifest {
304 format: "nmd",
305 byte_length: data.len(),
306 metadata,
307 global_track_count,
308 keyframe_bundles,
309 payload,
310 diagnostics: vec![NmdDiagnostic {
311 level: "warning".to_owned(),
312 code: "NMD_MOTION_DTO".to_owned(),
313 message: "NMD protobuf was parsed as a motion DTO; exporter roundtrip is not implemented yet.".to_owned(),
314 }],
315 })
316}
317
318fn count_keyframe_bundle(
319 data: &[u8],
320 counts: &mut NmdKeyframeBundleCounts,
321 payload: &mut NmdPayloadSummary,
322) -> Result<(), ImportError> {
323 let mut r = ProtoReader { data, pos: 0 };
324 let mut oneof_payload = None;
325 let mut saw_len_field = false;
326 while !r.is_eof() {
327 let Some((field, wire_type)) = r.read_key()? else {
328 break;
329 };
330 if wire_type == WIRE_LEN {
331 saw_len_field = true;
332 if matches!(field, 1 | 2 | 3 | 5 | 6 | 7 | 9) {
333 oneof_payload = Some((field, r.peek_len()?));
334 }
335 }
336 r.skip_value(wire_type)?;
337 }
338
339 match oneof_payload {
340 Some((1, bytes)) => {
341 counts.accessory += 1;
342 let frames = read_len_messages(bytes, 2)?
343 .into_iter()
344 .map(parse_accessory_keyframe)
345 .collect::<Result<Vec<_>, _>>()?;
346 payload.accessory_keyframes += frames.len();
347 payload.accessory_frames.extend(frames);
348 }
349 Some((2, bytes)) => {
350 counts.bone += 1;
351 count_bone_bundle_payload(bytes, payload)?;
352 }
353 Some((3, bytes)) => {
354 counts.camera += 1;
355 let frames = read_len_messages(bytes, 2)?
356 .into_iter()
357 .map(parse_camera_keyframe)
358 .collect::<Result<Vec<_>, _>>()?;
359 payload.camera_keyframes += frames.len();
360 payload.camera_frames.extend(frames);
361 }
362 Some((5, bytes)) => {
363 counts.light += 1;
364 let frames = read_len_messages(bytes, 2)?
365 .into_iter()
366 .map(parse_light_keyframe)
367 .collect::<Result<Vec<_>, _>>()?;
368 payload.light_keyframes += frames.len();
369 payload.light_frames.extend(frames);
370 }
371 Some((6, bytes)) => {
372 counts.model += 1;
373 let frames = read_len_messages(bytes, 2)?
374 .into_iter()
375 .map(parse_model_keyframe)
376 .collect::<Result<Vec<_>, _>>()?;
377 payload.model_keyframes += frames.len();
378 payload.model_frames.extend(frames);
379 }
380 Some((7, bytes)) => {
381 counts.morph += 1;
382 count_morph_bundle_payload(bytes, payload)?;
383 }
384 Some((9, bytes)) => {
385 counts.self_shadow += 1;
386 let frames = read_len_messages(bytes, 2)?
387 .into_iter()
388 .map(parse_self_shadow_keyframe)
389 .collect::<Result<Vec<_>, _>>()?;
390 payload.self_shadow_keyframes += frames.len();
391 payload.self_shadow_frames.extend(frames);
392 }
393 Some((_, _)) => counts.unknown += 1,
394 None if saw_len_field => counts.unknown += 1,
395 None => counts.unknown += 1,
396 }
397 Ok(())
398}
399
400fn count_bone_bundle_payload(
401 data: &[u8],
402 payload: &mut NmdPayloadSummary,
403) -> Result<(), ImportError> {
404 payload.bone_local_tracks += count_len_field(data, 2)?;
405 let frames = read_len_messages(data, 3)?
406 .into_iter()
407 .map(parse_bone_keyframe)
408 .collect::<Result<Vec<_>, _>>()?;
409 payload.bone_keyframes += frames.len();
410 payload.bone_frames.extend(frames);
411 Ok(())
412}
413
414fn count_morph_bundle_payload(
415 data: &[u8],
416 payload: &mut NmdPayloadSummary,
417) -> Result<(), ImportError> {
418 payload.morph_local_tracks += count_len_field(data, 2)?;
419 let frames = read_len_messages(data, 3)?
420 .into_iter()
421 .map(parse_morph_keyframe)
422 .collect::<Result<Vec<_>, _>>()?;
423 payload.morph_keyframes += frames.len();
424 payload.morph_frames.extend(frames);
425 Ok(())
426}
427
428fn count_len_field(data: &[u8], target_field: u32) -> Result<usize, ImportError> {
429 let mut r = ProtoReader { data, pos: 0 };
430 let mut count = 0usize;
431 while !r.is_eof() {
432 let Some((field, wire_type)) = r.read_key()? else {
433 break;
434 };
435 if field == target_field && wire_type == WIRE_LEN {
436 count += 1;
437 }
438 r.skip_value(wire_type)?;
439 }
440 Ok(count)
441}
442
443fn read_len_messages(data: &[u8], target_field: u32) -> Result<Vec<&[u8]>, ImportError> {
444 let mut r = ProtoReader { data, pos: 0 };
445 let mut messages = Vec::new();
446 while !r.is_eof() {
447 let Some((field, wire_type)) = r.read_key()? else {
448 break;
449 };
450 if field == target_field && wire_type == WIRE_LEN {
451 messages.push(r.peek_len()?);
452 }
453 r.skip_value(wire_type)?;
454 }
455 Ok(messages)
456}
457
458fn parse_common(data: &[u8]) -> Result<NmdKeyframeCommon, ImportError> {
459 let mut r = ProtoReader { data, pos: 0 };
460 let mut common = NmdKeyframeCommon::default();
461 while !r.is_eof() {
462 let Some((field, wire_type)) = r.read_key()? else {
463 break;
464 };
465 match (field, wire_type) {
466 (2, WIRE_VARINT) => common.frame_index = r.read_varint()?,
467 (3, WIRE_VARINT) => common.layer_index = Some(read_u32_varint(&mut r)?),
468 (4, WIRE_VARINT) => common.selected = Some(r.read_bool()?),
469 _ => r.skip_value(wire_type)?,
470 }
471 }
472 Ok(common)
473}
474
475fn parse_accessory_keyframe(data: &[u8]) -> Result<NmdAccessoryKeyframe, ImportError> {
476 let mut r = ProtoReader { data, pos: 0 };
477 let mut frame = NmdAccessoryKeyframe::default();
478 while !r.is_eof() {
479 let Some((field, wire_type)) = r.read_key()? else {
480 break;
481 };
482 match (field, wire_type) {
483 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
484 (2, WIRE_VARINT) => frame.track_index = r.read_varint()?,
485 (3, WIRE_LEN) => frame.translation = parse_vec3(r.read_len()?)?,
486 (4, WIRE_LEN) => frame.orientation = parse_vec4(r.read_len()?)?,
487 (5, WIRE_FIXED32) => frame.scale_factor = r.read_f32()?,
488 (6, WIRE_FIXED32) => frame.opacity = r.read_f32()?,
489 (7, WIRE_LEN) => frame
490 .effect_parameters
491 .push(parse_effect_parameter(r.read_len()?)?),
492 (8, WIRE_LEN) => frame.binding = Some(parse_model_binding(r.read_len()?)?),
493 (9, WIRE_VARINT) => frame.visible = Some(r.read_bool()?),
494 (10, WIRE_VARINT) => frame.shadow_enabled = Some(r.read_bool()?),
495 (11, WIRE_VARINT) => frame.add_blending_enabled = Some(r.read_bool()?),
496 _ => r.skip_value(wire_type)?,
497 }
498 }
499 Ok(frame)
500}
501
502fn parse_bone_keyframe(data: &[u8]) -> Result<NmdBoneKeyframe, ImportError> {
503 let mut r = ProtoReader { data, pos: 0 };
504 let mut frame = NmdBoneKeyframe::default();
505 while !r.is_eof() {
506 let Some((field, wire_type)) = r.read_key()? else {
507 break;
508 };
509 match (field, wire_type) {
510 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
511 (2, WIRE_VARINT) => frame.track_index = r.read_varint()?,
512 (3, WIRE_LEN) => frame.local_translation = parse_vec3(r.read_len()?)?,
513 (4, WIRE_LEN) => frame.local_orientation = parse_vec4(r.read_len()?)?,
514 (5, WIRE_LEN) => frame.interpolation = Some(parse_bone_interpolation(r.read_len()?)?),
515 (6, WIRE_VARINT) => frame.stage_index = Some(read_u32_varint(&mut r)?),
516 (7, WIRE_VARINT) => frame.physics_simulation_enabled = Some(r.read_bool()?),
517 _ => r.skip_value(wire_type)?,
518 }
519 }
520 Ok(frame)
521}
522
523fn parse_morph_keyframe(data: &[u8]) -> Result<NmdMorphKeyframe, ImportError> {
524 let mut r = ProtoReader { data, pos: 0 };
525 let mut frame = NmdMorphKeyframe::default();
526 while !r.is_eof() {
527 let Some((field, wire_type)) = r.read_key()? else {
528 break;
529 };
530 match (field, wire_type) {
531 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
532 (2, WIRE_VARINT) => frame.track_index = r.read_varint()?,
533 (3, WIRE_FIXED32) => frame.weight = r.read_f32()?,
534 (4, WIRE_LEN) => frame.interpolation = Some(parse_morph_interpolation(r.read_len()?)?),
535 _ => r.skip_value(wire_type)?,
536 }
537 }
538 Ok(frame)
539}
540
541fn parse_camera_keyframe(data: &[u8]) -> Result<NmdCameraKeyframe, ImportError> {
542 let mut r = ProtoReader { data, pos: 0 };
543 let mut frame = NmdCameraKeyframe::default();
544 while !r.is_eof() {
545 let Some((field, wire_type)) = r.read_key()? else {
546 break;
547 };
548 match (field, wire_type) {
549 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
550 (2, WIRE_LEN) => frame.look_at = parse_vec3(r.read_len()?)?,
551 (3, WIRE_LEN) => frame.angle = parse_vec3(r.read_len()?)?,
552 (4, WIRE_FIXED32) => frame.fov = r.read_f32()?,
553 (5, WIRE_FIXED32) => frame.distance = r.read_f32()?,
554 (6, WIRE_LEN) => frame.interpolation = Some(parse_camera_interpolation(r.read_len()?)?),
555 (7, WIRE_VARINT) => frame.stage_index = Some(read_u32_varint(&mut r)?),
556 (8, WIRE_VARINT) => frame.perspective_view_enabled = Some(r.read_bool()?),
557 _ => r.skip_value(wire_type)?,
558 }
559 }
560 Ok(frame)
561}
562
563fn parse_light_keyframe(data: &[u8]) -> Result<NmdLightKeyframe, ImportError> {
564 let mut r = ProtoReader { data, pos: 0 };
565 let mut frame = NmdLightKeyframe::default();
566 while !r.is_eof() {
567 let Some((field, wire_type)) = r.read_key()? else {
568 break;
569 };
570 match (field, wire_type) {
571 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
572 (2, WIRE_LEN) => frame.color = parse_vec3(r.read_len()?)?,
573 (3, WIRE_LEN) => frame.direction = parse_vec3(r.read_len()?)?,
574 _ => r.skip_value(wire_type)?,
575 }
576 }
577 Ok(frame)
578}
579
580fn parse_model_keyframe(data: &[u8]) -> Result<NmdModelKeyframe, ImportError> {
581 let mut r = ProtoReader { data, pos: 0 };
582 let mut frame = NmdModelKeyframe::default();
583 while !r.is_eof() {
584 let Some((field, wire_type)) = r.read_key()? else {
585 break;
586 };
587 match (field, wire_type) {
588 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
589 (2, WIRE_VARINT) => frame.visible = r.read_bool()?,
590 (3, WIRE_LEN) => {
591 frame.constraint_state_count += 1;
592 frame
593 .constraint_states
594 .push(parse_constraint_state(r.read_len()?)?);
595 }
596 (4, WIRE_LEN) => {
597 frame.effect_parameter_count += 1;
598 frame
599 .effect_parameters
600 .push(parse_effect_parameter(r.read_len()?)?);
601 }
602 (5, WIRE_LEN) => {
603 frame.binding_count += 1;
604 frame.bindings.push(parse_model_binding(r.read_len()?)?);
605 }
606 (6, WIRE_LEN) => frame.edge = Some(parse_edge(r.read_len()?)?),
607 (7, WIRE_VARINT) => frame.add_blending_enabled = Some(r.read_bool()?),
608 (8, WIRE_VARINT) => frame.physics_simulation_enabled = Some(r.read_bool()?),
609 _ => r.skip_value(wire_type)?,
610 }
611 }
612 Ok(frame)
613}
614
615fn parse_self_shadow_keyframe(data: &[u8]) -> Result<NmdSelfShadowKeyframe, ImportError> {
616 let mut r = ProtoReader { data, pos: 0 };
617 let mut frame = NmdSelfShadowKeyframe::default();
618 while !r.is_eof() {
619 let Some((field, wire_type)) = r.read_key()? else {
620 break;
621 };
622 match (field, wire_type) {
623 (1, WIRE_LEN) => frame.common = parse_common(r.read_len()?)?,
624 (2, WIRE_VARINT) => frame.enabled = r.read_bool()?,
625 (3, WIRE_VARINT) => frame.mode = read_i32_varint(&mut r)?,
626 (4, WIRE_FIXED32) => frame.distance = r.read_f32()?,
627 _ => r.skip_value(wire_type)?,
628 }
629 }
630 Ok(frame)
631}
632
633fn parse_bone_interpolation(data: &[u8]) -> Result<NmdBoneKeyframeInterpolation, ImportError> {
634 let mut r = ProtoReader { data, pos: 0 };
635 let mut interpolation = NmdBoneKeyframeInterpolation::default();
636 while !r.is_eof() {
637 let Some((field, wire_type)) = r.read_key()? else {
638 break;
639 };
640 match (field, wire_type) {
641 (1, WIRE_LEN) => interpolation.x = Some(parse_interpolation_unit(r.read_len()?)?),
642 (2, WIRE_LEN) => interpolation.y = Some(parse_interpolation_unit(r.read_len()?)?),
643 (3, WIRE_LEN) => interpolation.z = Some(parse_interpolation_unit(r.read_len()?)?),
644 (4, WIRE_LEN) => {
645 interpolation.orientation = Some(parse_interpolation_unit(r.read_len()?)?)
646 }
647 _ => r.skip_value(wire_type)?,
648 }
649 }
650 Ok(interpolation)
651}
652
653fn parse_morph_interpolation(data: &[u8]) -> Result<NmdInterpolationUnit, ImportError> {
654 let mut r = ProtoReader { data, pos: 0 };
655 let mut interpolation = None;
656 while !r.is_eof() {
657 let Some((field, wire_type)) = r.read_key()? else {
658 break;
659 };
660 match (field, wire_type) {
661 (1, WIRE_LEN) => interpolation = Some(parse_interpolation_unit(r.read_len()?)?),
662 _ => r.skip_value(wire_type)?,
663 }
664 }
665 Ok(interpolation.unwrap_or_default())
666}
667
668fn parse_camera_interpolation(data: &[u8]) -> Result<NmdCameraKeyframeInterpolation, ImportError> {
669 let mut r = ProtoReader { data, pos: 0 };
670 let mut interpolation = NmdCameraKeyframeInterpolation::default();
671 while !r.is_eof() {
672 let Some((field, wire_type)) = r.read_key()? else {
673 break;
674 };
675 match (field, wire_type) {
676 (1, WIRE_LEN) => interpolation.x = Some(parse_interpolation_unit(r.read_len()?)?),
677 (2, WIRE_LEN) => interpolation.y = Some(parse_interpolation_unit(r.read_len()?)?),
678 (3, WIRE_LEN) => interpolation.z = Some(parse_interpolation_unit(r.read_len()?)?),
679 (4, WIRE_LEN) => interpolation.angle = Some(parse_interpolation_unit(r.read_len()?)?),
680 (5, WIRE_LEN) => interpolation.fov = Some(parse_interpolation_unit(r.read_len()?)?),
681 (6, WIRE_LEN) => {
682 interpolation.distance = Some(parse_interpolation_unit(r.read_len()?)?)
683 }
684 _ => r.skip_value(wire_type)?,
685 }
686 }
687 Ok(interpolation)
688}
689
690fn parse_interpolation_unit(data: &[u8]) -> Result<NmdInterpolationUnit, ImportError> {
691 let mut r = ProtoReader { data, pos: 0 };
692 let mut unit = NmdInterpolationUnit::default();
693 while !r.is_eof() {
694 let Some((field, wire_type)) = r.read_key()? else {
695 break;
696 };
697 match (field, wire_type) {
698 (1, WIRE_LEN) => unit.integer = Some(parse_integer_interpolation(r.read_len()?)?),
699 (2, WIRE_LEN) => unit.float = Some(parse_float_interpolation(r.read_len()?)?),
700 _ => r.skip_value(wire_type)?,
701 }
702 }
703 Ok(unit)
704}
705
706fn parse_integer_interpolation(data: &[u8]) -> Result<[u32; 4], ImportError> {
707 let mut r = ProtoReader { data, pos: 0 };
708 let mut values = [0; 4];
709 while !r.is_eof() {
710 let Some((field, wire_type)) = r.read_key()? else {
711 break;
712 };
713 match (field, wire_type) {
714 (1, WIRE_VARINT) => values[0] = read_u32_varint(&mut r)?,
715 (2, WIRE_VARINT) => values[1] = read_u32_varint(&mut r)?,
716 (3, WIRE_VARINT) => values[2] = read_u32_varint(&mut r)?,
717 (4, WIRE_VARINT) => values[3] = read_u32_varint(&mut r)?,
718 _ => r.skip_value(wire_type)?,
719 }
720 }
721 Ok(values)
722}
723
724fn parse_float_interpolation(data: &[u8]) -> Result<[f32; 4], ImportError> {
725 let mut r = ProtoReader { data, pos: 0 };
726 let mut values = [0.0; 4];
727 while !r.is_eof() {
728 let Some((field, wire_type)) = r.read_key()? else {
729 break;
730 };
731 match (field, wire_type) {
732 (1, WIRE_FIXED32) => values[0] = r.read_f32()?,
733 (2, WIRE_FIXED32) => values[1] = r.read_f32()?,
734 (3, WIRE_FIXED32) => values[2] = r.read_f32()?,
735 (4, WIRE_FIXED32) => values[3] = r.read_f32()?,
736 _ => r.skip_value(wire_type)?,
737 }
738 }
739 Ok(values)
740}
741
742fn parse_constraint_state(data: &[u8]) -> Result<NmdConstraintState, ImportError> {
743 let mut r = ProtoReader { data, pos: 0 };
744 let mut state = NmdConstraintState::default();
745 while !r.is_eof() {
746 let Some((field, wire_type)) = r.read_key()? else {
747 break;
748 };
749 match (field, wire_type) {
750 (1, WIRE_VARINT) => state.track_index = r.read_varint()?,
751 (2, WIRE_VARINT) => state.enabled = r.read_bool()?,
752 _ => r.skip_value(wire_type)?,
753 }
754 }
755 Ok(state)
756}
757
758fn parse_effect_parameter(data: &[u8]) -> Result<NmdEffectParameter, ImportError> {
759 let mut r = ProtoReader { data, pos: 0 };
760 let mut parameter = NmdEffectParameter::default();
761 while !r.is_eof() {
762 let Some((field, wire_type)) = r.read_key()? else {
763 break;
764 };
765 match (field, wire_type) {
766 (1, WIRE_VARINT) => parameter.track_index = r.read_varint()?,
767 (2, WIRE_VARINT) => parameter.bool_value = Some(r.read_bool()?),
768 (3, WIRE_VARINT) => parameter.int_value = Some(read_i32_varint(&mut r)?),
769 (4, WIRE_FIXED32) => parameter.float_value = Some(r.read_f32()?),
770 (5, WIRE_LEN) => parameter.vector_value = Some(parse_vec4(r.read_len()?)?),
771 _ => r.skip_value(wire_type)?,
772 }
773 }
774 Ok(parameter)
775}
776
777fn parse_model_binding(data: &[u8]) -> Result<NmdModelBinding, ImportError> {
778 let mut r = ProtoReader { data, pos: 0 };
779 let mut binding = NmdModelBinding::default();
780 while !r.is_eof() {
781 let Some((field, wire_type)) = r.read_key()? else {
782 break;
783 };
784 match (field, wire_type) {
785 (1, WIRE_VARINT) => binding.local_bone_track_index = Some(r.read_varint()?),
786 (2, WIRE_VARINT) => binding.global_object_track_index = r.read_varint()?,
787 (3, WIRE_VARINT) => binding.global_bone_track_index = r.read_varint()?,
788 _ => r.skip_value(wire_type)?,
789 }
790 }
791 Ok(binding)
792}
793
794fn parse_edge(data: &[u8]) -> Result<NmdEdge, ImportError> {
795 let mut r = ProtoReader { data, pos: 0 };
796 let mut edge = NmdEdge::default();
797 while !r.is_eof() {
798 let Some((field, wire_type)) = r.read_key()? else {
799 break;
800 };
801 match (field, wire_type) {
802 (1, WIRE_LEN) => edge.color = parse_vec4(r.read_len()?)?,
803 (2, WIRE_FIXED32) => edge.scale_factor = r.read_f32()?,
804 _ => r.skip_value(wire_type)?,
805 }
806 }
807 Ok(edge)
808}
809
810fn parse_vec3(data: &[u8]) -> Result<[f32; 3], ImportError> {
811 let mut r = ProtoReader { data, pos: 0 };
812 let mut values = [0.0; 3];
813 while !r.is_eof() {
814 let Some((field, wire_type)) = r.read_key()? else {
815 break;
816 };
817 match (field, wire_type) {
818 (1, WIRE_FIXED32) => values[0] = r.read_f32()?,
819 (2, WIRE_FIXED32) => values[1] = r.read_f32()?,
820 (3, WIRE_FIXED32) => values[2] = r.read_f32()?,
821 _ => r.skip_value(wire_type)?,
822 }
823 }
824 Ok(values)
825}
826
827fn parse_vec4(data: &[u8]) -> Result<[f32; 4], ImportError> {
828 let mut r = ProtoReader { data, pos: 0 };
829 let mut values = [0.0; 4];
830 while !r.is_eof() {
831 let Some((field, wire_type)) = r.read_key()? else {
832 break;
833 };
834 match (field, wire_type) {
835 (1, WIRE_FIXED32) => values[0] = r.read_f32()?,
836 (2, WIRE_FIXED32) => values[1] = r.read_f32()?,
837 (3, WIRE_FIXED32) => values[2] = r.read_f32()?,
838 (4, WIRE_FIXED32) => values[3] = r.read_f32()?,
839 _ => r.skip_value(wire_type)?,
840 }
841 }
842 Ok(values)
843}
844
845fn read_u32_varint(r: &mut ProtoReader<'_>) -> Result<u32, ImportError> {
846 let value = r.read_varint()?;
847 if value > u64::from(u32::MAX) {
848 return Err(ImportError::UnsupportedFormat {
849 format: "NMD",
850 detail: "uint32 value overflows u32",
851 });
852 }
853 Ok(value as u32)
854}
855
856fn read_i32_varint(r: &mut ProtoReader<'_>) -> Result<i32, ImportError> {
857 let value = r.read_varint()?;
858 if value > u64::from(u32::MAX) {
859 return Err(ImportError::UnsupportedFormat {
860 format: "NMD",
861 detail: "int32 varint value overflows u32",
862 });
863 }
864 Ok(value as u32 as i32)
865}
866
867const WIRE_VARINT: u8 = 0;
868const WIRE_FIXED64: u8 = 1;
869const WIRE_LEN: u8 = 2;
870const WIRE_FIXED32: u8 = 5;
871
872struct ProtoReader<'a> {
873 data: &'a [u8],
874 pos: usize,
875}
876
877impl<'a> ProtoReader<'a> {
878 fn is_eof(&self) -> bool {
879 self.pos >= self.data.len()
880 }
881
882 fn read_key(&mut self) -> Result<Option<(u32, u8)>, ImportError> {
883 if self.is_eof() {
884 return Ok(None);
885 }
886 let key = self.read_varint()?;
887 let field = key >> 3;
888 if field == 0 {
889 return Err(ImportError::UnsupportedFormat {
890 format: "NMD",
891 detail: "protobuf field number must be non-zero",
892 });
893 }
894 if field > 0x1fff_ffff {
895 return Err(ImportError::UnsupportedFormat {
896 format: "NMD",
897 detail: "protobuf field number exceeds the supported range",
898 });
899 }
900 Ok(Some((field as u32, (key & 0x7) as u8)))
901 }
902
903 fn read_varint(&mut self) -> Result<u64, ImportError> {
904 let mut value = 0u64;
905 for shift in (0..64).step_by(7) {
906 let byte = self.read_u8()?;
907 if shift == 63 && byte > 1 {
908 return Err(ImportError::UnsupportedFormat {
909 format: "NMD",
910 detail: "varint overflows u64",
911 });
912 }
913 value |= u64::from(byte & 0x7f) << shift;
914 if byte & 0x80 == 0 {
915 return Ok(value);
916 }
917 }
918 Err(ImportError::UnsupportedFormat {
919 format: "NMD",
920 detail: "varint is too long",
921 })
922 }
923
924 fn read_u8(&mut self) -> Result<u8, ImportError> {
925 if self.pos >= self.data.len() {
926 return Err(ImportError::UnexpectedEof(1));
927 }
928 let byte = self.data[self.pos];
929 self.pos += 1;
930 Ok(byte)
931 }
932
933 fn read_len(&mut self) -> Result<&'a [u8], ImportError> {
934 let raw_len = self.read_varint()?;
935 if raw_len > usize::MAX as u64 {
936 return Err(ImportError::UnsupportedFormat {
937 format: "NMD",
938 detail: "length does not fit in usize",
939 });
940 }
941 let len = raw_len as usize;
942 let end = self
943 .pos
944 .checked_add(len)
945 .ok_or(ImportError::SectionOverflow)?;
946 if end > self.data.len() {
947 return Err(ImportError::UnexpectedEof(end - self.data.len()));
948 }
949 let bytes = &self.data[self.pos..end];
950 self.pos = end;
951 Ok(bytes)
952 }
953
954 fn peek_len(&self) -> Result<&'a [u8], ImportError> {
955 let mut copy = ProtoReader {
956 data: self.data,
957 pos: self.pos,
958 };
959 copy.read_len()
960 }
961
962 fn skip_len(&mut self) -> Result<(), ImportError> {
963 self.read_len().map(|_| ())
964 }
965
966 fn read_f32(&mut self) -> Result<f32, ImportError> {
967 let end = self
968 .pos
969 .checked_add(4)
970 .ok_or(ImportError::SectionOverflow)?;
971 if end > self.data.len() {
972 return Err(ImportError::UnexpectedEof(end - self.data.len()));
973 }
974 let bytes = &self.data[self.pos..end];
975 self.pos = end;
976 let value = f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
977 if !value.is_finite() {
978 return Err(ImportError::UnsupportedFormat {
979 format: "NMD",
980 detail: "float value is not finite",
981 });
982 }
983 Ok(value)
984 }
985
986 fn read_bool(&mut self) -> Result<bool, ImportError> {
987 Ok(self.read_varint()? != 0)
988 }
989
990 fn skip_value(&mut self, wire_type: u8) -> Result<(), ImportError> {
991 match wire_type {
992 WIRE_VARINT => {
993 self.read_varint()?;
994 Ok(())
995 }
996 WIRE_FIXED64 => {
997 self.skip_bytes(8)?;
998 Ok(())
999 }
1000 WIRE_LEN => self.skip_len(),
1001 WIRE_FIXED32 => {
1002 self.skip_bytes(4)?;
1003 Ok(())
1004 }
1005 _ => Err(ImportError::UnsupportedFormat {
1006 format: "NMD",
1007 detail: "unsupported protobuf wire type",
1008 }),
1009 }
1010 }
1011
1012 fn skip_bytes(&mut self, len: usize) -> Result<(), ImportError> {
1013 let end = self
1014 .pos
1015 .checked_add(len)
1016 .ok_or(ImportError::SectionOverflow)?;
1017 if end > self.data.len() {
1018 return Err(ImportError::UnexpectedEof(end - self.data.len()));
1019 }
1020 self.pos = end;
1021 Ok(())
1022 }
1023}
1024
1025fn default_nmd_format() -> &'static str {
1026 "nmd"
1027}
1028
1029#[cfg(test)]
1030mod tests {
1031 use super::*;
1032
1033 fn key(field: u32, wire_type: u8) -> u8 {
1034 ((field << 3) | u32::from(wire_type)) as u8
1035 }
1036
1037 fn push_len(out: &mut Vec<u8>, field: u32, bytes: &[u8]) {
1038 out.push(key(field, WIRE_LEN));
1039 push_varint(out, bytes.len() as u64);
1040 out.extend_from_slice(bytes);
1041 }
1042
1043 fn push_varint(out: &mut Vec<u8>, mut value: u64) {
1044 while value >= 0x80 {
1045 out.push((value as u8 & 0x7f) | 0x80);
1046 value >>= 7;
1047 }
1048 out.push(value as u8);
1049 }
1050
1051 fn push_varint_field(out: &mut Vec<u8>, field: u32, value: u64) {
1052 out.push(key(field, WIRE_VARINT));
1053 push_varint(out, value);
1054 }
1055
1056 fn push_f32_field(out: &mut Vec<u8>, field: u32, value: f32) {
1057 out.push(key(field, WIRE_FIXED32));
1058 out.extend_from_slice(&value.to_le_bytes());
1059 }
1060
1061 fn common(frame_index: u64) -> Vec<u8> {
1062 let mut out = Vec::new();
1063 push_varint_field(&mut out, 2, frame_index);
1064 out
1065 }
1066
1067 fn vec3(x: f32, y: f32, z: f32) -> Vec<u8> {
1068 let mut out = Vec::new();
1069 push_f32_field(&mut out, 1, x);
1070 push_f32_field(&mut out, 2, y);
1071 push_f32_field(&mut out, 3, z);
1072 out
1073 }
1074
1075 fn vec4(x: f32, y: f32, z: f32, w: f32) -> Vec<u8> {
1076 let mut out = vec3(x, y, z);
1077 push_f32_field(&mut out, 4, w);
1078 out
1079 }
1080
1081 fn integer_interp(x0: u32, y0: u32, x1: u32, y1: u32) -> Vec<u8> {
1082 let mut out = Vec::new();
1083 push_varint_field(&mut out, 1, u64::from(x0));
1084 push_varint_field(&mut out, 2, u64::from(y0));
1085 push_varint_field(&mut out, 3, u64::from(x1));
1086 push_varint_field(&mut out, 4, u64::from(y1));
1087 out
1088 }
1089
1090 fn float_interp(x0: f32, y0: f32, x1: f32, y1: f32) -> Vec<u8> {
1091 let mut out = Vec::new();
1092 push_f32_field(&mut out, 1, x0);
1093 push_f32_field(&mut out, 2, y0);
1094 push_f32_field(&mut out, 3, x1);
1095 push_f32_field(&mut out, 4, y1);
1096 out
1097 }
1098
1099 fn interp_unit_integer(values: [u32; 4]) -> Vec<u8> {
1100 let mut out = Vec::new();
1101 push_len(
1102 &mut out,
1103 1,
1104 &integer_interp(values[0], values[1], values[2], values[3]),
1105 );
1106 out
1107 }
1108
1109 fn interp_unit_float(values: [f32; 4]) -> Vec<u8> {
1110 let mut out = Vec::new();
1111 push_len(
1112 &mut out,
1113 2,
1114 &float_interp(values[0], values[1], values[2], values[3]),
1115 );
1116 out
1117 }
1118
1119 fn push_bundle(out: &mut Vec<u8>, field: u32) {
1120 let bundle = vec![key(field, WIRE_LEN), 0];
1121 push_len(out, 5, &bundle);
1122 }
1123
1124 fn push_bone_bundle(out: &mut Vec<u8>, local_track_count: usize, keyframe_count: usize) {
1125 let mut bone = Vec::new();
1126 for _ in 0..local_track_count {
1127 push_len(&mut bone, 2, &[]);
1128 }
1129 for _ in 0..keyframe_count {
1130 push_len(&mut bone, 3, &[]);
1131 }
1132 let mut unit = Vec::new();
1133 push_len(&mut unit, 2, &bone);
1134 push_len(out, 5, &unit);
1135 }
1136
1137 fn push_morph_bundle(out: &mut Vec<u8>, local_track_count: usize, keyframe_count: usize) {
1138 let mut morph = Vec::new();
1139 for _ in 0..local_track_count {
1140 push_len(&mut morph, 2, &[]);
1141 }
1142 for _ in 0..keyframe_count {
1143 push_len(&mut morph, 3, &[]);
1144 }
1145 let mut unit = Vec::new();
1146 push_len(&mut unit, 7, &morph);
1147 push_len(out, 5, &unit);
1148 }
1149
1150 fn push_len_keyframe_payload(out: &mut Vec<u8>, field: u32, keyframe_count: usize) {
1151 let mut payload = Vec::new();
1152 for _ in 0..keyframe_count {
1153 push_len(&mut payload, 2, &[]);
1154 }
1155 let mut unit = Vec::new();
1156 push_len(&mut unit, field, &payload);
1157 push_len(out, 5, &unit);
1158 }
1159
1160 #[test]
1161 fn parses_nmd_top_level_motion_manifest() {
1162 let mut data = Vec::new();
1163 push_len(&mut data, 2, b"main-model");
1164 data.push(key(3, WIRE_FIXED32));
1165 data.extend_from_slice(&60.0f32.to_le_bytes());
1166 push_len(&mut data, 4, &[key(1, WIRE_VARINT), 1]);
1167 push_bone_bundle(&mut data, 2, 3);
1168 push_bundle(&mut data, 3);
1169 push_morph_bundle(&mut data, 1, 2);
1170 push_len_keyframe_payload(&mut data, 5, 4);
1171 push_len_keyframe_payload(&mut data, 6, 5);
1172 push_len_keyframe_payload(&mut data, 9, 6);
1173
1174 let parsed = parse_nmd_manifest(&data).unwrap();
1175
1176 assert_eq!(parsed.format, "nmd");
1177 assert_eq!(parsed.byte_length, data.len());
1178 assert_eq!(
1179 parsed.metadata.main_object_name.as_deref(),
1180 Some("main-model")
1181 );
1182 assert_eq!(parsed.metadata.preferred_fps, Some(60.0));
1183 assert_eq!(parsed.global_track_count, 1);
1184 assert_eq!(parsed.keyframe_bundles.bone, 1);
1185 assert_eq!(parsed.keyframe_bundles.camera, 1);
1186 assert_eq!(parsed.keyframe_bundles.light, 1);
1187 assert_eq!(parsed.keyframe_bundles.model, 1);
1188 assert_eq!(parsed.keyframe_bundles.morph, 1);
1189 assert_eq!(parsed.keyframe_bundles.self_shadow, 1);
1190 assert_eq!(parsed.payload.bone_local_tracks, 2);
1191 assert_eq!(parsed.payload.bone_keyframes, 3);
1192 assert_eq!(parsed.payload.light_keyframes, 4);
1193 assert_eq!(parsed.payload.model_keyframes, 5);
1194 assert_eq!(parsed.payload.morph_local_tracks, 1);
1195 assert_eq!(parsed.payload.morph_keyframes, 2);
1196 assert_eq!(parsed.payload.self_shadow_keyframes, 6);
1197 assert_eq!(parsed.diagnostics[0].code, "NMD_MOTION_DTO");
1198 }
1199
1200 #[test]
1201 fn parses_nmd_keyframe_value_payloads() {
1202 let mut data = Vec::new();
1203
1204 let mut accessory_frame = Vec::new();
1205 push_len(&mut accessory_frame, 1, &common(9));
1206 push_varint_field(&mut accessory_frame, 2, 2);
1207 push_len(&mut accessory_frame, 3, &vec3(7.0, 8.0, 9.0));
1208 push_len(&mut accessory_frame, 4, &vec4(0.0, 0.0, 0.0, 1.0));
1209 push_f32_field(&mut accessory_frame, 5, 1.25);
1210 push_f32_field(&mut accessory_frame, 6, 0.75);
1211 let mut accessory_effect = Vec::new();
1212 push_varint_field(&mut accessory_effect, 1, 8);
1213 push_f32_field(&mut accessory_effect, 4, 0.5);
1214 push_len(&mut accessory_frame, 7, &accessory_effect);
1215 let mut accessory_binding = Vec::new();
1216 push_varint_field(&mut accessory_binding, 1, 1);
1217 push_varint_field(&mut accessory_binding, 2, 2);
1218 push_varint_field(&mut accessory_binding, 3, 3);
1219 push_len(&mut accessory_frame, 8, &accessory_binding);
1220 push_varint_field(&mut accessory_frame, 9, 1);
1221 push_varint_field(&mut accessory_frame, 10, 0);
1222 push_varint_field(&mut accessory_frame, 11, 1);
1223 let mut accessory_bundle = Vec::new();
1224 push_len(&mut accessory_bundle, 2, &accessory_frame);
1225 let mut accessory_unit = Vec::new();
1226 push_len(&mut accessory_unit, 1, &accessory_bundle);
1227 push_len(&mut data, 5, &accessory_unit);
1228
1229 let mut bone_frame = Vec::new();
1230 push_len(&mut bone_frame, 1, &common(10));
1231 push_varint_field(&mut bone_frame, 2, 3);
1232 push_len(&mut bone_frame, 3, &vec3(1.0, 2.0, 3.0));
1233 push_len(&mut bone_frame, 4, &vec4(0.0, 0.0, 0.0, 1.0));
1234 let mut bone_interpolation = Vec::new();
1235 push_len(
1236 &mut bone_interpolation,
1237 1,
1238 &interp_unit_integer([1, 2, 3, 4]),
1239 );
1240 push_len(
1241 &mut bone_interpolation,
1242 4,
1243 &interp_unit_float([0.1, 0.2, 0.3, 0.4]),
1244 );
1245 push_len(&mut bone_frame, 5, &bone_interpolation);
1246 push_varint_field(&mut bone_frame, 6, 2);
1247 push_varint_field(&mut bone_frame, 7, 1);
1248 let mut bone_bundle = Vec::new();
1249 push_len(&mut bone_bundle, 3, &bone_frame);
1250 let mut bone_unit = Vec::new();
1251 push_len(&mut bone_unit, 2, &bone_bundle);
1252 push_len(&mut data, 5, &bone_unit);
1253
1254 let mut morph_frame = Vec::new();
1255 push_len(&mut morph_frame, 1, &common(11));
1256 push_varint_field(&mut morph_frame, 2, 4);
1257 push_f32_field(&mut morph_frame, 3, 0.5);
1258 let mut morph_interpolation = Vec::new();
1259 push_len(
1260 &mut morph_interpolation,
1261 1,
1262 &interp_unit_integer([5, 6, 7, 8]),
1263 );
1264 push_len(&mut morph_frame, 4, &morph_interpolation);
1265 let mut morph_bundle = Vec::new();
1266 push_len(&mut morph_bundle, 3, &morph_frame);
1267 let mut morph_unit = Vec::new();
1268 push_len(&mut morph_unit, 7, &morph_bundle);
1269 push_len(&mut data, 5, &morph_unit);
1270
1271 let mut camera_frame = Vec::new();
1272 push_len(&mut camera_frame, 1, &common(12));
1273 push_len(&mut camera_frame, 2, &vec3(4.0, 5.0, 6.0));
1274 push_len(&mut camera_frame, 3, &vec3(0.1, 0.2, 0.3));
1275 push_f32_field(&mut camera_frame, 4, 45.0);
1276 push_f32_field(&mut camera_frame, 5, 20.0);
1277 let mut camera_interpolation = Vec::new();
1278 push_len(
1279 &mut camera_interpolation,
1280 6,
1281 &interp_unit_float([1.1, 1.2, 1.3, 1.4]),
1282 );
1283 push_len(&mut camera_frame, 6, &camera_interpolation);
1284 push_varint_field(&mut camera_frame, 8, 1);
1285 let mut camera_bundle = Vec::new();
1286 push_len(&mut camera_bundle, 2, &camera_frame);
1287 let mut camera_unit = Vec::new();
1288 push_len(&mut camera_unit, 3, &camera_bundle);
1289 push_len(&mut data, 5, &camera_unit);
1290
1291 let mut light_frame = Vec::new();
1292 push_len(&mut light_frame, 1, &common(13));
1293 push_len(&mut light_frame, 2, &vec3(0.8, 0.7, 0.6));
1294 push_len(&mut light_frame, 3, &vec3(-1.0, -2.0, -3.0));
1295 let mut light_bundle = Vec::new();
1296 push_len(&mut light_bundle, 2, &light_frame);
1297 let mut light_unit = Vec::new();
1298 push_len(&mut light_unit, 5, &light_bundle);
1299 push_len(&mut data, 5, &light_unit);
1300
1301 let mut model_frame = Vec::new();
1302 push_len(&mut model_frame, 1, &common(14));
1303 push_varint_field(&mut model_frame, 2, 1);
1304 let mut constraint = Vec::new();
1305 push_varint_field(&mut constraint, 1, 9);
1306 push_varint_field(&mut constraint, 2, 1);
1307 push_len(&mut model_frame, 3, &constraint);
1308 let mut effect = Vec::new();
1309 push_varint_field(&mut effect, 1, 10);
1310 push_len(&mut effect, 5, &vec4(0.1, 0.2, 0.3, 0.4));
1311 push_len(&mut model_frame, 4, &effect);
1312 let mut binding = Vec::new();
1313 push_varint_field(&mut binding, 1, 11);
1314 push_varint_field(&mut binding, 2, 12);
1315 push_varint_field(&mut binding, 3, 13);
1316 push_len(&mut model_frame, 5, &binding);
1317 let mut edge = Vec::new();
1318 push_len(&mut edge, 1, &vec4(1.0, 0.5, 0.25, 0.75));
1319 push_f32_field(&mut edge, 2, 1.5);
1320 push_len(&mut model_frame, 6, &edge);
1321 push_varint_field(&mut model_frame, 8, 0);
1322 let mut model_bundle = Vec::new();
1323 push_len(&mut model_bundle, 2, &model_frame);
1324 let mut model_unit = Vec::new();
1325 push_len(&mut model_unit, 6, &model_bundle);
1326 push_len(&mut data, 5, &model_unit);
1327
1328 let mut shadow_frame = Vec::new();
1329 push_len(&mut shadow_frame, 1, &common(15));
1330 push_varint_field(&mut shadow_frame, 2, 1);
1331 push_varint_field(&mut shadow_frame, 3, 2);
1332 push_f32_field(&mut shadow_frame, 4, 30.0);
1333 let mut shadow_bundle = Vec::new();
1334 push_len(&mut shadow_bundle, 2, &shadow_frame);
1335 let mut shadow_unit = Vec::new();
1336 push_len(&mut shadow_unit, 9, &shadow_bundle);
1337 push_len(&mut data, 5, &shadow_unit);
1338
1339 let parsed = parse_nmd_manifest(&data).unwrap();
1340
1341 assert_eq!(parsed.payload.accessory_keyframes, 1);
1342 assert_eq!(parsed.payload.accessory_frames[0].common.frame_index, 9);
1343 assert_eq!(parsed.payload.accessory_frames[0].track_index, 2);
1344 assert_eq!(
1345 parsed.payload.accessory_frames[0].translation,
1346 [7.0, 8.0, 9.0]
1347 );
1348 assert_eq!(parsed.payload.accessory_frames[0].scale_factor, 1.25);
1349 assert_eq!(parsed.payload.accessory_frames[0].opacity, 0.75);
1350 assert_eq!(
1351 parsed.payload.accessory_frames[0].effect_parameters[0].float_value,
1352 Some(0.5)
1353 );
1354 assert_eq!(
1355 parsed.payload.accessory_frames[0]
1356 .binding
1357 .as_ref()
1358 .map(|binding| binding.global_bone_track_index),
1359 Some(3)
1360 );
1361 assert_eq!(parsed.payload.accessory_frames[0].visible, Some(true));
1362 assert_eq!(
1363 parsed.payload.accessory_frames[0].shadow_enabled,
1364 Some(false)
1365 );
1366 assert_eq!(
1367 parsed.payload.accessory_frames[0].add_blending_enabled,
1368 Some(true)
1369 );
1370 assert_eq!(parsed.payload.bone_frames[0].common.frame_index, 10);
1371 assert_eq!(parsed.payload.bone_frames[0].track_index, 3);
1372 assert_eq!(
1373 parsed.payload.bone_frames[0].local_translation,
1374 [1.0, 2.0, 3.0]
1375 );
1376 assert_eq!(
1377 parsed.payload.bone_frames[0].local_orientation,
1378 [0.0, 0.0, 0.0, 1.0]
1379 );
1380 assert_eq!(
1381 parsed.payload.bone_frames[0]
1382 .interpolation
1383 .as_ref()
1384 .and_then(|interpolation| interpolation.x.as_ref())
1385 .and_then(|unit| unit.integer),
1386 Some([1, 2, 3, 4])
1387 );
1388 assert_eq!(
1389 parsed.payload.bone_frames[0]
1390 .interpolation
1391 .as_ref()
1392 .and_then(|interpolation| interpolation.orientation.as_ref())
1393 .and_then(|unit| unit.float),
1394 Some([0.1, 0.2, 0.3, 0.4])
1395 );
1396 assert_eq!(parsed.payload.bone_frames[0].stage_index, Some(2));
1397 assert_eq!(
1398 parsed.payload.bone_frames[0].physics_simulation_enabled,
1399 Some(true)
1400 );
1401 assert_eq!(parsed.payload.morph_frames[0].weight, 0.5);
1402 assert_eq!(
1403 parsed.payload.morph_frames[0]
1404 .interpolation
1405 .as_ref()
1406 .and_then(|unit| unit.integer),
1407 Some([5, 6, 7, 8])
1408 );
1409 assert_eq!(parsed.payload.camera_frames[0].look_at, [4.0, 5.0, 6.0]);
1410 assert_eq!(parsed.payload.camera_frames[0].fov, 45.0);
1411 assert_eq!(
1412 parsed.payload.camera_frames[0]
1413 .interpolation
1414 .as_ref()
1415 .and_then(|interpolation| interpolation.distance.as_ref())
1416 .and_then(|unit| unit.float),
1417 Some([1.1, 1.2, 1.3, 1.4])
1418 );
1419 assert_eq!(
1420 parsed.payload.camera_frames[0].perspective_view_enabled,
1421 Some(true)
1422 );
1423 assert_eq!(parsed.payload.light_frames[0].color, [0.8, 0.7, 0.6]);
1424 assert!(parsed.payload.model_frames[0].visible);
1425 assert_eq!(parsed.payload.model_frames[0].constraint_state_count, 1);
1426 assert_eq!(
1427 parsed.payload.model_frames[0].constraint_states[0].track_index,
1428 9
1429 );
1430 assert!(parsed.payload.model_frames[0].constraint_states[0].enabled);
1431 assert_eq!(
1432 parsed.payload.model_frames[0].effect_parameters[0].track_index,
1433 10
1434 );
1435 assert_eq!(
1436 parsed.payload.model_frames[0].effect_parameters[0].vector_value,
1437 Some([0.1, 0.2, 0.3, 0.4])
1438 );
1439 assert_eq!(
1440 parsed.payload.model_frames[0].bindings[0].local_bone_track_index,
1441 Some(11)
1442 );
1443 assert_eq!(
1444 parsed.payload.model_frames[0].bindings[0].global_object_track_index,
1445 12
1446 );
1447 assert_eq!(
1448 parsed.payload.model_frames[0]
1449 .edge
1450 .as_ref()
1451 .map(|edge| edge.scale_factor),
1452 Some(1.5)
1453 );
1454 assert_eq!(
1455 parsed.payload.model_frames[0].physics_simulation_enabled,
1456 Some(false)
1457 );
1458 assert_eq!(parsed.payload.self_shadow_frames[0].mode, 2);
1459 assert_eq!(parsed.payload.self_shadow_frames[0].distance, 30.0);
1460 }
1461
1462 #[test]
1463 fn rejects_truncated_nmd_len_field() {
1464 let result = parse_nmd_manifest(&[key(2, WIRE_LEN), 5, b'a']);
1465
1466 assert!(matches!(result, Err(ImportError::UnexpectedEof(4))));
1467 }
1468
1469 #[test]
1470 fn rejects_empty_nmd_manifest() {
1471 let result = parse_nmd_manifest(&[]);
1472
1473 assert!(matches!(result, Err(ImportError::UnexpectedEof(1))));
1474 }
1475
1476 #[test]
1477 fn rejects_overflowing_varint_without_panicking() {
1478 let result = parse_nmd_manifest(&[0xff; 10]);
1479
1480 assert!(matches!(
1481 result,
1482 Err(ImportError::UnsupportedFormat {
1483 format: "NMD",
1484 detail: "varint overflows u64"
1485 })
1486 ));
1487 }
1488
1489 #[test]
1490 fn rejects_zero_protobuf_field_number() {
1491 let result = parse_nmd_manifest(&[0]);
1492
1493 assert!(matches!(
1494 result,
1495 Err(ImportError::UnsupportedFormat {
1496 format: "NMD",
1497 detail: "protobuf field number must be non-zero"
1498 })
1499 ));
1500 }
1501
1502 #[test]
1503 fn rejects_oversized_protobuf_field_number() {
1504 let mut data = Vec::new();
1505 push_varint(&mut data, (0x2000_0000u64 << 3) | u64::from(WIRE_VARINT));
1506
1507 let result = parse_nmd_manifest(&data);
1508
1509 assert!(matches!(
1510 result,
1511 Err(ImportError::UnsupportedFormat {
1512 format: "NMD",
1513 detail: "protobuf field number exceeds the supported range"
1514 })
1515 ));
1516 }
1517
1518 #[test]
1519 fn keyframe_bundle_uses_last_oneof_field() {
1520 let mut bone = Vec::new();
1521 push_len(&mut bone, 3, &[]);
1522 let mut morph = Vec::new();
1523 push_len(&mut morph, 3, &[]);
1524 push_len(&mut morph, 3, &[]);
1525
1526 let mut unit = Vec::new();
1527 push_len(&mut unit, 2, &bone);
1528 push_len(&mut unit, 7, &morph);
1529 let mut data = Vec::new();
1530 push_len(&mut data, 5, &unit);
1531
1532 let parsed = parse_nmd_manifest(&data).unwrap();
1533
1534 assert_eq!(parsed.keyframe_bundles.bone, 0);
1535 assert_eq!(parsed.keyframe_bundles.morph, 1);
1536 assert_eq!(parsed.payload.bone_keyframes, 0);
1537 assert_eq!(parsed.payload.morph_keyframes, 2);
1538 }
1539
1540 #[test]
1541 fn unknown_len_field_does_not_override_known_keyframe_bundle_oneof() {
1542 let mut bone = Vec::new();
1543 push_len(&mut bone, 3, &[]);
1544
1545 let mut unit = Vec::new();
1546 push_len(&mut unit, 2, &bone);
1547 push_len(&mut unit, 10, b"unknown");
1548 let mut data = Vec::new();
1549 push_len(&mut data, 5, &unit);
1550
1551 let parsed = parse_nmd_manifest(&data).unwrap();
1552
1553 assert_eq!(parsed.keyframe_bundles.bone, 1);
1554 assert_eq!(parsed.keyframe_bundles.unknown, 0);
1555 assert_eq!(parsed.payload.bone_keyframes, 1);
1556 }
1557
1558 #[test]
1559 fn parses_negative_int32_varint_values() {
1560 let mut shadow_frame = Vec::new();
1561 push_len(&mut shadow_frame, 1, &common(1));
1562 push_varint_field(&mut shadow_frame, 3, u64::from(u32::MAX));
1563
1564 let mut shadow_bundle = Vec::new();
1565 push_len(&mut shadow_bundle, 2, &shadow_frame);
1566 let mut shadow_unit = Vec::new();
1567 push_len(&mut shadow_unit, 9, &shadow_bundle);
1568 let mut data = Vec::new();
1569 push_len(&mut data, 5, &shadow_unit);
1570
1571 let parsed = parse_nmd_manifest(&data).unwrap();
1572
1573 assert_eq!(parsed.payload.self_shadow_frames[0].mode, -1);
1574 }
1575
1576 #[test]
1577 fn rejects_int32_varint_values_that_exceed_u32() {
1578 let mut shadow_frame = Vec::new();
1579 push_len(&mut shadow_frame, 1, &common(1));
1580 push_varint_field(&mut shadow_frame, 3, u64::from(u32::MAX) + 1);
1581
1582 let mut shadow_bundle = Vec::new();
1583 push_len(&mut shadow_bundle, 2, &shadow_frame);
1584 let mut shadow_unit = Vec::new();
1585 push_len(&mut shadow_unit, 9, &shadow_bundle);
1586 let mut data = Vec::new();
1587 push_len(&mut data, 5, &shadow_unit);
1588
1589 let result = parse_nmd_manifest(&data);
1590
1591 assert!(matches!(
1592 result,
1593 Err(ImportError::UnsupportedFormat {
1594 format: "NMD",
1595 detail: "int32 varint value overflows u32"
1596 })
1597 ));
1598 }
1599
1600 #[test]
1601 fn rejects_nonfinite_keyframe_float_values() {
1602 let mut accessory_frame = Vec::new();
1603 push_len(&mut accessory_frame, 1, &common(1));
1604 push_f32_field(&mut accessory_frame, 5, f32::NAN);
1605
1606 let mut accessory_bundle = Vec::new();
1607 push_len(&mut accessory_bundle, 2, &accessory_frame);
1608 let mut accessory_unit = Vec::new();
1609 push_len(&mut accessory_unit, 1, &accessory_bundle);
1610 let mut data = Vec::new();
1611 push_len(&mut data, 5, &accessory_unit);
1612
1613 let result = parse_nmd_manifest(&data);
1614
1615 assert!(matches!(
1616 result,
1617 Err(ImportError::UnsupportedFormat {
1618 format: "NMD",
1619 detail: "float value is not finite"
1620 })
1621 ));
1622 }
1623
1624 #[test]
1625 fn rejects_nonfinite_preferred_fps() {
1626 let mut data = Vec::new();
1627 data.push(key(3, WIRE_FIXED32));
1628 data.extend_from_slice(&f32::INFINITY.to_le_bytes());
1629
1630 let result = parse_nmd_manifest(&data);
1631
1632 assert!(matches!(
1633 result,
1634 Err(ImportError::UnsupportedFormat {
1635 format: "NMD",
1636 detail: "float value is not finite"
1637 })
1638 ));
1639 }
1640
1641 #[test]
1642 fn parses_multibyte_length_delimited_fields() {
1643 let mut data = Vec::new();
1644 let name = vec![b'a'; 130];
1645 push_len(&mut data, 2, &name);
1646
1647 let parsed = parse_nmd_manifest(&data).unwrap();
1648 let expected = "a".repeat(130);
1649
1650 assert_eq!(
1651 parsed.metadata.main_object_name.as_deref(),
1652 Some(expected.as_str())
1653 );
1654 }
1655}