1use crate::{Map, ValueContainer};
2use serde::{Deserialize, Serialize};
3use theframework::prelude::{FxHashMap, FxHashSet};
4use uuid::Uuid;
5use vek::Vec2;
6
7#[derive(Serialize, Deserialize, Clone, Debug)]
8pub struct Keyform {
9 pub vertex_positions: Vec<(u32, Vec2<f32>)>,
10}
11
12#[derive(Serialize, Deserialize, Clone, Debug)]
13pub struct SoftRig {
14 pub id: Uuid,
15 pub name: String,
16 pub keyforms: Vec<Keyform>,
17 pub in_editor_playlist: bool,
18
19 pub values: ValueContainer,
20}
21
22impl SoftRig {
23 pub fn new(name: String) -> Self {
24 Self {
25 id: Uuid::new_v4(),
26 name,
27 keyforms: vec![],
28 in_editor_playlist: true,
29 values: ValueContainer::default(),
30 }
31 }
32}
33
34#[derive(Clone, Debug)]
35pub struct SoftRigAnimator {
36 pub keyframes: Vec<Uuid>,
37 pub total_duration: f32, pub progress: f32, pub playing: bool,
40 pub loop_playback: bool,
41}
42
43impl Default for SoftRigAnimator {
44 fn default() -> Self {
45 Self::new()
46 }
47}
48
49impl SoftRigAnimator {
50 pub fn new() -> Self {
51 Self {
52 keyframes: Vec::new(),
53 total_duration: 1.0,
54 progress: 0.0,
55 playing: true,
56 loop_playback: true,
57 }
58 }
59
60 pub fn set_progress(&mut self, value: f32) {
61 self.progress = value.clamp(0.0, 1.0);
62 }
63
64 pub fn tick(&mut self, delta_time: f32) {
65 if !self.playing || self.keyframes.len() < 2 || self.total_duration <= 0.0 {
66 return;
67 }
68
69 self.progress += delta_time / self.total_duration;
70
71 if self.progress >= 1.0 {
72 if self.loop_playback {
73 self.progress %= 1.0;
74 } else {
75 self.progress = 1.0;
76 self.playing = false;
77 }
78 }
79 }
80
81 pub fn get_blended_rig(&self, map: &Map) -> Option<SoftRig> {
82 let len = self.keyframes.len();
83 if len == 0 {
84 return None;
85 } else if len == 1 {
86 return map.softrigs.get(&self.keyframes[0]).cloned();
87 }
88
89 let t = self.progress * (len as f32 - 1.0);
90 let i = t.floor() as usize;
91 let frac = t - i as f32;
92
93 let id_a = self.keyframes.get(i)?;
94 let id_b = self.keyframes.get(i + 1).unwrap_or(id_a);
95
96 let rig_a = map.softrigs.get(id_a)?;
97 let rig_b = map.softrigs.get(id_b)?;
98
99 Some(Self::blend_softrigs(rig_a, rig_b, frac, map))
100 }
101
102 pub fn blend_softrigs(a: &SoftRig, b: &SoftRig, t: f32, map: &Map) -> SoftRig {
103 let positions_a: FxHashMap<u32, Vec2<f32>> = a
104 .keyforms
105 .iter()
106 .flat_map(|k| k.vertex_positions.iter().copied())
107 .collect();
108
109 let positions_b: FxHashMap<u32, Vec2<f32>> = b
110 .keyforms
111 .iter()
112 .flat_map(|k| k.vertex_positions.iter().copied())
113 .collect();
114
115 let all_ids: FxHashSet<u32> = positions_a
116 .keys()
117 .chain(positions_b.keys())
118 .copied()
119 .collect();
120
121 let mut blended_keyform = Keyform {
122 vertex_positions: Vec::new(),
123 };
124
125 for id in all_ids {
126 let pa = positions_a
127 .get(&id)
128 .copied()
129 .or_else(|| map.find_vertex(id).map(|v| Vec2::new(v.x, v.y)));
130 let pb = positions_b
131 .get(&id)
132 .copied()
133 .or_else(|| map.find_vertex(id).map(|v| Vec2::new(v.x, v.y)));
134
135 let blended = match (pa, pb) {
136 (Some(a), Some(b)) => Vec2::lerp(a, b, t),
137 (Some(a), None) => a,
138 (None, Some(b)) => b,
139 _ => continue,
140 };
141
142 blended_keyform.vertex_positions.push((id, blended));
143 }
144
145 SoftRig {
146 id: Uuid::new_v4(),
147 name: "Blended".into(),
148 keyforms: vec![blended_keyform],
149 in_editor_playlist: false,
150 values: ValueContainer::default(),
151 }
152 }
153}