Skip to main content

mmd_anim_format/
nmd.rs

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}