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