1use super::interpolation::interpolate_with_blend;
7use super::state::{AnimationState, LcgRng};
8use super::types::{Lerp, Quat, ResolvedTrack, Vec3};
9
10#[derive(Debug, Clone)]
12pub struct AnimSequence {
13 pub id: u16,
15 pub sub_id: u16,
17 pub duration: u32,
19 pub movement_speed: f32,
21 pub flags: u32,
23 pub frequency: u16,
25 pub replay_min: u32,
27 pub replay_max: u32,
29 pub blend_time: u32,
31 pub variation_next: i16,
33 pub alias_next: u16,
35}
36
37impl AnimSequence {
38 pub fn calculate_repeats(&self, rng: &mut LcgRng) -> i32 {
40 if self.replay_max <= self.replay_min {
41 return self.replay_min as i32;
42 }
43 let range = (self.replay_max - self.replay_min) as f32;
44 self.replay_min as i32 + (range * rng.next_f32()) as i32
45 }
46
47 pub fn is_alias(&self) -> bool {
49 (self.flags & 0x40) != 0 && (self.flags & 0x20) == 0
50 }
51}
52
53#[derive(Debug, Clone)]
55pub struct ResolvedBone {
56 pub bone_id: i32,
58 pub flags: u32,
60 pub parent_bone: i16,
62 pub translation: ResolvedTrack<Vec3>,
64 pub rotation: ResolvedTrack<Quat>,
66 pub scale: ResolvedTrack<Vec3>,
68 pub pivot: Vec3,
70}
71
72#[derive(Debug, Clone)]
77pub struct AnimationManager {
78 global_sequence_durations: Vec<u32>,
80 global_sequence_times: Vec<f64>,
82 sequences: Vec<AnimSequence>,
84 bones: Vec<ResolvedBone>,
86 current_animation: AnimationState,
88 next_animation: AnimationState,
90 blend_factor: f32,
92 rng: LcgRng,
94}
95
96impl AnimationManager {
97 pub fn new(
104 global_sequence_durations: Vec<u32>,
105 sequences: Vec<AnimSequence>,
106 bones: Vec<ResolvedBone>,
107 ) -> Self {
108 let global_sequence_times = vec![0.0; global_sequence_durations.len()];
109
110 let stand_index = sequences.iter().position(|s| s.id == 0);
112
113 let mut rng = LcgRng::default();
114 let mut current_animation = AnimationState::new(stand_index);
115
116 if let Some(idx) = stand_index {
118 current_animation.repeat_times = sequences[idx].calculate_repeats(&mut rng);
119 }
120
121 Self {
122 global_sequence_durations,
123 global_sequence_times,
124 sequences,
125 bones,
126 current_animation,
127 next_animation: AnimationState::none(),
128 blend_factor: 1.0,
129 rng,
130 }
131 }
132
133 pub fn empty() -> Self {
135 Self {
136 global_sequence_durations: Vec::new(),
137 global_sequence_times: Vec::new(),
138 sequences: Vec::new(),
139 bones: Vec::new(),
140 current_animation: AnimationState::none(),
141 next_animation: AnimationState::none(),
142 blend_factor: 1.0,
143 rng: LcgRng::default(),
144 }
145 }
146
147 pub fn update(&mut self, delta_time_ms: f64) {
149 self.current_animation.animation_time += delta_time_ms;
151
152 for (i, time) in self.global_sequence_times.iter_mut().enumerate() {
154 *time += delta_time_ms;
155 if self.global_sequence_durations[i] > 0 {
156 *time %= self.global_sequence_durations[i] as f64;
157 }
158 }
159
160 self.update_animation_transitions();
162 }
163
164 fn update_animation_transitions(&mut self) {
166 let Some(current_idx) = self.current_animation.animation_index else {
167 return;
168 };
169
170 if current_idx >= self.sequences.len() {
171 return;
172 }
173
174 let main_variation = &self.sequences[self.current_animation.main_variation_index];
175
176 if self.next_animation.animation_index.is_none()
178 && main_variation.variation_next > -1
179 && self.current_animation.repeat_times <= 0
180 {
181 self.select_next_variation();
182 } else if self.current_animation.repeat_times > 0 {
183 self.next_animation = self.current_animation.clone();
185 self.next_animation.repeat_times -= 1;
186 }
187
188 let current_seq = &self.sequences[current_idx];
190 let time_left = current_seq.duration as f64 - self.current_animation.animation_time;
191
192 if let Some(next_idx) = self.next_animation.animation_index {
193 let next_seq = &self.sequences[next_idx];
194 let blend_time = next_seq.blend_time as f64;
195
196 if blend_time > 0.0 && time_left < blend_time {
197 self.next_animation.animation_time =
198 (blend_time - time_left) % next_seq.duration as f64;
199 self.blend_factor = (time_left / blend_time) as f32;
200 } else {
201 self.blend_factor = 1.0;
202 }
203 }
204
205 if self.current_animation.animation_time >= current_seq.duration as f64 {
207 self.current_animation.repeat_times -= 1;
208
209 if let Some(next_idx) = self.next_animation.animation_index {
210 let resolved_idx = self.resolve_alias(next_idx);
212 self.next_animation.animation_index = Some(resolved_idx);
213
214 self.current_animation = self.next_animation.clone();
216 self.next_animation = AnimationState::none();
217 self.blend_factor = 1.0;
218 } else if current_seq.duration > 0 {
219 self.current_animation.animation_time %= current_seq.duration as f64;
221 }
222 }
223 }
224
225 fn select_next_variation(&mut self) {
227 let main_idx = self.current_animation.main_variation_index;
228 let probability = (self.rng.next_f32() * 0x7fff as f32) as u16;
229
230 let mut calc_prob = 0u16;
231 let mut next_index = main_idx;
232
233 loop {
234 let seq = &self.sequences[next_index];
235 calc_prob = calc_prob.saturating_add(seq.frequency);
236
237 if calc_prob >= probability || seq.variation_next < 0 {
238 break;
239 }
240
241 let potential_next = seq.variation_next as usize;
242 if potential_next >= self.sequences.len() {
243 break;
244 }
245
246 if Some(potential_next) != self.current_animation.animation_index {
248 next_index = potential_next;
249 } else if seq.variation_next >= 0 {
250 next_index = seq.variation_next as usize;
251 }
252 }
253
254 self.next_animation.animation_index = Some(next_index);
255 self.next_animation.animation_time = 0.0;
256 self.next_animation.main_variation_index = main_idx;
257 self.next_animation.repeat_times =
258 self.sequences[next_index].calculate_repeats(&mut self.rng);
259 }
260
261 fn resolve_alias(&self, index: usize) -> usize {
263 let mut current = index;
264 let mut iterations = 0;
265
266 while iterations < 100 {
267 if current >= self.sequences.len() {
269 return index;
270 }
271
272 let seq = &self.sequences[current];
273 if !seq.is_alias() {
274 return current;
275 }
276
277 current = seq.alias_next as usize;
278 iterations += 1;
279 }
280
281 index
282 }
283
284 pub fn set_animation_id(&mut self, id: u16) {
286 let index = self.sequences.iter().position(|s| s.id == id);
287
288 if let Some(idx) = index {
289 self.current_animation = AnimationState::new(Some(idx));
290 self.current_animation.repeat_times =
291 self.sequences[idx].calculate_repeats(&mut self.rng);
292 self.next_animation = AnimationState::none();
293 self.blend_factor = 1.0;
294 }
295 }
296
297 pub fn set_animation_index(&mut self, index: usize) {
299 if index < self.sequences.len() {
300 self.current_animation = AnimationState::new(Some(index));
301 self.current_animation.repeat_times =
302 self.sequences[index].calculate_repeats(&mut self.rng);
303 self.next_animation = AnimationState::none();
304 self.blend_factor = 1.0;
305 }
306 }
307
308 pub fn get_animation_ids(&self) -> Vec<u16> {
310 self.sequences.iter().map(|s| s.id).collect()
311 }
312
313 pub fn current_time(&self) -> f64 {
315 self.current_animation.animation_time
316 }
317
318 pub fn current_animation_index(&self) -> Option<usize> {
320 self.current_animation.animation_index
321 }
322
323 pub fn bone_count(&self) -> usize {
325 self.bones.len()
326 }
327
328 pub fn sequence_count(&self) -> usize {
330 self.sequences.len()
331 }
332
333 pub fn get_current_value<T: Lerp + Clone + Default>(&self, track: &ResolvedTrack<T>) -> T {
335 self.get_current_value_with_default(track, T::default())
336 }
337
338 pub fn get_current_value_with_default<T: Lerp + Clone>(
340 &self,
341 track: &ResolvedTrack<T>,
342 default: T,
343 ) -> T {
344 let Some(current_idx) = self.current_animation.animation_index else {
345 return default;
346 };
347
348 interpolate_with_blend(
349 track,
350 current_idx,
351 self.current_animation.animation_time,
352 self.next_animation.animation_index,
353 self.next_animation.animation_time,
354 self.blend_factor,
355 &self.global_sequence_times,
356 default,
357 )
358 }
359
360 pub fn get_bone_translation(&self, bone_index: usize) -> Vec3 {
362 if bone_index >= self.bones.len() {
363 return Vec3::ZERO;
364 }
365 self.get_current_value_with_default(&self.bones[bone_index].translation, Vec3::ZERO)
366 }
367
368 pub fn get_bone_rotation(&self, bone_index: usize) -> Quat {
370 if bone_index >= self.bones.len() {
371 return Quat::IDENTITY;
372 }
373 self.get_current_value_with_default(&self.bones[bone_index].rotation, Quat::IDENTITY)
374 }
375
376 pub fn get_bone_scale(&self, bone_index: usize) -> Vec3 {
378 if bone_index >= self.bones.len() {
379 return Vec3::ONE;
380 }
381 self.get_current_value_with_default(&self.bones[bone_index].scale, Vec3::ONE)
382 }
383
384 pub fn bones(&self) -> &[ResolvedBone] {
386 &self.bones
387 }
388
389 pub fn sequences(&self) -> &[AnimSequence] {
391 &self.sequences
392 }
393
394 pub fn global_times(&self) -> &[f64] {
396 &self.global_sequence_times
397 }
398
399 pub fn blend_factor(&self) -> f32 {
401 self.blend_factor
402 }
403}
404
405pub struct AnimationManagerBuilder;
407
408impl AnimationManagerBuilder {
409 pub fn from_model(model: &crate::M2Model, data: &[u8]) -> crate::Result<AnimationManager> {
434 use std::io::Cursor;
435
436 let global_sequence_durations: Vec<u32> = model.global_sequences.to_vec();
438
439 let sequences: Vec<AnimSequence> = model
441 .animations
442 .iter()
443 .map(|seq| {
444 let duration = seq
448 .end_timestamp
449 .map(|end| end.saturating_sub(seq.start_timestamp))
450 .unwrap_or(seq.start_timestamp);
451
452 let (replay_min, replay_max) = seq
454 .replay
455 .map(|r| (r.minimum as u32, r.maximum as u32))
456 .unwrap_or((0, 0));
457
458 AnimSequence {
459 id: seq.animation_id,
460 sub_id: seq.sub_animation_id,
461 duration,
462 movement_speed: seq.movement_speed,
463 flags: seq.flags,
464 frequency: seq.frequency as u16,
465 replay_min,
466 replay_max,
467 blend_time: 150, variation_next: seq.next_animation.unwrap_or(-1),
469 alias_next: seq.aliasing.unwrap_or(0),
470 }
471 })
472 .collect();
473
474 let num_sequences = sequences.len();
475
476 let mut cursor = Cursor::new(data);
478 let mut bones = Vec::with_capacity(model.bones.len());
479
480 for bone in &model.bones {
481 let translation =
483 Self::resolve_vec3_track(&bone.translation, &mut cursor, num_sequences)?;
484
485 let rotation = Self::resolve_quat_track(&bone.rotation, &mut cursor, num_sequences)?;
487
488 let scale = Self::resolve_vec3_track(&bone.scale, &mut cursor, num_sequences)?;
490
491 bones.push(ResolvedBone {
492 bone_id: bone.bone_id,
493 flags: bone.flags.bits(),
494 parent_bone: bone.parent_bone,
495 translation,
496 rotation,
497 scale,
498 pivot: Vec3::new(bone.pivot.x, bone.pivot.y, bone.pivot.z),
499 });
500 }
501
502 Ok(AnimationManager::new(
503 global_sequence_durations,
504 sequences,
505 bones,
506 ))
507 }
508
509 fn resolve_vec3_track<R: std::io::Read + std::io::Seek>(
511 track: &crate::chunks::m2_track::M2TrackVec3,
512 reader: &mut R,
513 num_sequences: usize,
514 ) -> crate::Result<ResolvedTrack<Vec3>> {
515 use crate::chunks::m2_track_resolver::M2TrackVec3Ext;
516
517 if !track.has_data() {
518 return Ok(ResolvedTrack::empty());
519 }
520
521 let (timestamps_flat, values_flat, ranges) = track.resolve_data(reader)?;
522
523 let values_vec3: Vec<Vec3> = values_flat
525 .into_iter()
526 .map(|v| Vec3::new(v.x, v.y, v.z))
527 .collect();
528
529 let global_sequence = if track.base.global_sequence == 0xFFFF {
531 -1i16
532 } else {
533 track.base.global_sequence as i16
534 };
535
536 if global_sequence >= 0 {
538 return Ok(ResolvedTrack {
539 interpolation_type: track.base.interpolation_type as u16,
540 global_sequence,
541 timestamps: vec![timestamps_flat],
542 values: vec![values_vec3],
543 });
544 }
545
546 let (timestamps, values) = Self::split_by_ranges(
548 timestamps_flat,
549 values_vec3,
550 ranges.as_deref(),
551 num_sequences,
552 );
553
554 Ok(ResolvedTrack {
555 interpolation_type: track.base.interpolation_type as u16,
556 global_sequence,
557 timestamps,
558 values,
559 })
560 }
561
562 fn resolve_quat_track<R: std::io::Read + std::io::Seek>(
564 track: &crate::chunks::m2_track::M2TrackQuat,
565 reader: &mut R,
566 num_sequences: usize,
567 ) -> crate::Result<ResolvedTrack<Quat>> {
568 use crate::chunks::m2_track_resolver::M2TrackQuatExt;
569
570 if !track.has_data() {
571 return Ok(ResolvedTrack::empty());
572 }
573
574 let (timestamps_flat, values_flat, ranges) = track.resolve_data(reader)?;
575
576 let values_quat: Vec<Quat> = values_flat
578 .into_iter()
579 .map(|q| {
580 let (x, y, z, w) = q.to_float_quaternion();
581 Quat::new(x, y, z, w).normalize()
582 })
583 .collect();
584
585 let global_sequence = if track.base.global_sequence == 0xFFFF {
587 -1i16
588 } else {
589 track.base.global_sequence as i16
590 };
591
592 if global_sequence >= 0 {
594 return Ok(ResolvedTrack {
595 interpolation_type: track.base.interpolation_type as u16,
596 global_sequence,
597 timestamps: vec![timestamps_flat],
598 values: vec![values_quat],
599 });
600 }
601
602 let (timestamps, values) = Self::split_by_ranges(
604 timestamps_flat,
605 values_quat,
606 ranges.as_deref(),
607 num_sequences,
608 );
609
610 Ok(ResolvedTrack {
611 interpolation_type: track.base.interpolation_type as u16,
612 global_sequence,
613 timestamps,
614 values,
615 })
616 }
617
618 fn split_by_ranges<T: Clone>(
623 timestamps_flat: Vec<u32>,
624 values_flat: Vec<T>,
625 ranges: Option<&[u32]>,
626 num_sequences: usize,
627 ) -> (Vec<Vec<u32>>, Vec<Vec<T>>) {
628 if let Some(ranges) = ranges {
629 let mut timestamps = Vec::with_capacity(num_sequences);
631 let mut values = Vec::with_capacity(num_sequences);
632
633 for i in 0..num_sequences {
634 let range_idx = i * 2;
635 if range_idx + 1 < ranges.len() {
636 let start = ranges[range_idx] as usize;
637 let end = ranges[range_idx + 1] as usize;
638
639 if start <= end && end <= timestamps_flat.len() && end <= values_flat.len() {
640 timestamps.push(timestamps_flat[start..end].to_vec());
641 values.push(values_flat[start..end].to_vec());
642 } else {
643 timestamps.push(Vec::new());
644 values.push(Vec::new());
645 }
646 } else {
647 timestamps.push(Vec::new());
648 values.push(Vec::new());
649 }
650 }
651
652 (timestamps, values)
653 } else {
654 let mut timestamps = Vec::with_capacity(num_sequences);
658 let mut values = Vec::with_capacity(num_sequences);
659
660 if !timestamps_flat.is_empty() {
662 timestamps.push(timestamps_flat);
663 values.push(values_flat);
664 }
665
666 while timestamps.len() < num_sequences {
668 timestamps.push(Vec::new());
669 values.push(Vec::new());
670 }
671
672 (timestamps, values)
673 }
674 }
675}
676
677#[cfg(test)]
678mod tests {
679 use super::*;
680
681 fn create_test_sequence(id: u16, duration: u32) -> AnimSequence {
682 AnimSequence {
683 id,
684 sub_id: 0,
685 duration,
686 movement_speed: 0.0,
687 flags: 0,
688 frequency: 0x7fff,
689 replay_min: 0,
690 replay_max: 0,
691 blend_time: 0,
692 variation_next: -1,
693 alias_next: 0,
694 }
695 }
696
697 #[test]
698 fn test_animation_manager_empty() {
699 let manager = AnimationManager::empty();
700 assert_eq!(manager.bone_count(), 0);
701 assert_eq!(manager.sequence_count(), 0);
702 assert_eq!(manager.current_animation_index(), None);
703 }
704
705 #[test]
706 fn test_animation_manager_basic() {
707 let sequences = vec![
708 create_test_sequence(0, 1000), create_test_sequence(4, 500), ];
711
712 let manager = AnimationManager::new(vec![], sequences, vec![]);
713
714 assert_eq!(manager.current_animation_index(), Some(0));
716 assert_eq!(manager.sequence_count(), 2);
717 }
718
719 #[test]
720 fn test_animation_update() {
721 let sequences = vec![create_test_sequence(0, 1000)];
722 let mut manager = AnimationManager::new(vec![], sequences, vec![]);
723
724 manager.update(500.0);
726 assert!((manager.current_time() - 500.0).abs() < 0.001);
727
728 manager.update(600.0);
730 assert!(manager.current_time() < 1000.0);
731 }
732
733 #[test]
734 fn test_set_animation() {
735 let sequences = vec![create_test_sequence(0, 1000), create_test_sequence(4, 500)];
736 let mut manager = AnimationManager::new(vec![], sequences, vec![]);
737
738 manager.set_animation_id(4);
739 assert_eq!(manager.current_animation_index(), Some(1));
740 assert!((manager.current_time() - 0.0).abs() < 0.001);
741 }
742
743 #[test]
744 fn test_global_sequences() {
745 let sequences = vec![create_test_sequence(0, 1000)];
746 let global_durations = vec![500, 1000];
747
748 let mut manager = AnimationManager::new(global_durations, sequences, vec![]);
749
750 manager.update(250.0);
752
753 let times = manager.global_times();
754 assert!((times[0] - 250.0).abs() < 0.001);
755 assert!((times[1] - 250.0).abs() < 0.001);
756
757 manager.update(300.0); let times = manager.global_times();
760 assert!((times[0] - 50.0).abs() < 0.001); assert!((times[1] - 550.0).abs() < 0.001); }
763
764 #[test]
765 fn test_bone_interpolation() {
766 let bone = ResolvedBone {
767 bone_id: 0,
768 flags: 0,
769 parent_bone: -1,
770 translation: ResolvedTrack {
771 interpolation_type: 1, global_sequence: -1,
773 timestamps: vec![vec![0, 100]],
774 values: vec![vec![Vec3::ZERO, Vec3::new(10.0, 0.0, 0.0)]],
775 },
776 rotation: ResolvedTrack::empty(),
777 scale: ResolvedTrack::empty(),
778 pivot: Vec3::ZERO,
779 };
780
781 let sequences = vec![create_test_sequence(0, 1000)];
782 let mut manager = AnimationManager::new(vec![], sequences, vec![bone]);
783
784 let trans = manager.get_bone_translation(0);
786 assert!((trans.x - 0.0).abs() < 0.001);
787
788 manager.update(50.0);
790 let trans = manager.get_bone_translation(0);
791 assert!((trans.x - 5.0).abs() < 0.001);
792
793 manager.update(50.0);
795 let trans = manager.get_bone_translation(0);
796 assert!((trans.x - 10.0).abs() < 0.001);
797 }
798}