1use ranim_core::{
2 animation::Eval,
3 traits::{Alignable, Interpolatable},
4};
5
6pub trait MorphRequirement: Alignable + Interpolatable + Clone {}
9impl<T: Alignable + Interpolatable + Clone> MorphRequirement for T {}
10pub trait MorphAnim: MorphRequirement + Sized + 'static {
15 fn morph<F: Fn(&mut Self)>(&mut self, f: F) -> Morph<Self>;
17 fn morph_from(&mut self, src: Self) -> Morph<Self>;
19 fn morph_to(&mut self, dst: Self) -> Morph<Self>;
21}
22impl<T: MorphRequirement + 'static> MorphAnim for T {
26 fn morph<F: Fn(&mut T)>(&mut self, f: F) -> Morph<T> {
27 let mut dst = self.clone();
28 (f)(&mut dst);
29 Morph::new(self.clone(), dst).apply_to(self)
30 }
31 fn morph_from(&mut self, s: T) -> Morph<T> {
32 Morph::new(s, self.clone()).apply_to(self)
33 }
34 fn morph_to(&mut self, d: T) -> Morph<T> {
35 Morph::new(self.clone(), d).apply_to(self)
36 }
37}
38pub struct Morph<T: MorphRequirement> {
43 src: T,
44 dst: T,
45 aligned_src: T,
46 aligned_dst: T,
47}
48impl<T: MorphRequirement> Morph<T> {
51 pub fn new(src: T, dst: T) -> Self {
53 let mut aligned_src = src.clone();
54 let mut aligned_dst = dst.clone();
55 if !aligned_src.is_aligned(&aligned_dst) {
56 aligned_src.align_with(&mut aligned_dst);
57 }
58 Self {
59 src,
60 dst,
61 aligned_src,
62 aligned_dst,
63 }
64 }
65}
66
67impl<T: MorphRequirement> Eval for Morph<T> {
69 type Output = T;
70
71 fn eval_alpha(&self, alpha: f64) -> Self::Output {
72 if alpha == 0.0 {
73 self.src.clone()
74 } else if 0.0 < alpha && alpha < 1.0 {
75 self.aligned_src.lerp(&self.aligned_dst, alpha)
76 } else if alpha == 1.0 {
77 self.dst.clone()
78 } else {
79 unreachable!()
80 }
81 }
82}
83