1use rustc_hash::{FxHashMap, FxHashSet};
2use slotmap::{SlotMap, new_key_type};
3
4use crate::action::AnimationAction;
5use crate::binding::{Rig, TargetPath};
6use crate::blending::{BlendEntry, FrameBlendState};
7use crate::clip::TrackData;
8use crate::events::{self, FiredEvent};
9use crate::target::AnimationTarget;
10use myth_core::NodeHandle;
11
12new_key_type! {
13 pub struct ActionHandle;
14}
15
16pub struct AnimationMixer {
40 actions: SlotMap<ActionHandle, AnimationAction>,
41 name_map: FxHashMap<String, ActionHandle>,
42 active_handles: Vec<ActionHandle>,
43
44 rig: Rig,
46
47 pub time: f32,
49 pub time_scale: f32,
51
52 blend_state: FrameBlendState,
54 fired_events: Vec<FiredEvent>,
56 animated_last_frame: FxHashSet<NodeHandle>,
59
60 morph_buffer: crate::values::MorphWeightData,
62
63 pub enabled: bool,
64}
65
66impl Default for AnimationMixer {
67 fn default() -> Self {
68 Self::new()
69 }
70}
71
72impl AnimationMixer {
73 #[must_use]
74 pub fn new() -> Self {
75 Self {
76 actions: SlotMap::with_key(),
77 name_map: FxHashMap::default(),
78 active_handles: Vec::new(),
79 rig: Rig {
80 bones: Vec::new(),
81 bone_paths: Vec::new(),
82 },
83 time: 0.0,
84 time_scale: 1.0,
85 blend_state: FrameBlendState::new(),
86 fired_events: Vec::new(),
87 animated_last_frame: FxHashSet::default(),
88 morph_buffer: crate::values::MorphWeightData::default(),
89 enabled: true,
90 }
91 }
92
93 pub fn set_rig(&mut self, rig: Rig) {
95 self.rig = rig;
96 }
97
98 #[must_use]
100 pub fn rig(&self) -> &Rig {
101 &self.rig
102 }
103
104 #[must_use]
106 pub fn list_animations(&self) -> Vec<String> {
107 self.name_map.keys().cloned().collect()
108 }
109
110 pub fn add_action(&mut self, action: AnimationAction) -> ActionHandle {
112 let name = action.clip().name.clone();
113 let handle = self.actions.insert(action);
114 self.name_map.insert(name, handle);
115 handle
116 }
117
118 #[must_use]
120 pub fn get_action(&self, name: &str) -> Option<&AnimationAction> {
121 let handle = *self.name_map.get(name)?;
122 self.actions.get(handle)
123 }
124
125 #[must_use]
127 pub fn get_action_by_handle(&self, handle: ActionHandle) -> Option<&AnimationAction> {
128 self.actions.get(handle)
129 }
130
131 pub fn action(&mut self, name: &str) -> Option<ActionControl<'_>> {
133 let handle = *self.name_map.get(name)?;
134 Some(ActionControl {
135 mixer: self,
136 handle,
137 })
138 }
139
140 pub fn any_action(&mut self) -> Option<ActionControl<'_>> {
142 if let Some((handle, _)) = self.actions.iter().next() {
143 Some(ActionControl {
144 mixer: self,
145 handle,
146 })
147 } else {
148 None
149 }
150 }
151
152 pub fn get_control(&mut self, handle: ActionHandle) -> Option<ActionControl<'_>> {
154 if self.actions.contains_key(handle) {
155 Some(ActionControl {
156 mixer: self,
157 handle,
158 })
159 } else {
160 None
161 }
162 }
163
164 pub fn get_control_by_name(&mut self, name: &str) -> Option<ActionControl<'_>> {
165 let handle = *self.name_map.get(name)?;
166 self.get_control(handle)
167 }
168
169 pub fn play(&mut self, name: &str) {
171 if let Some(&handle) = self.name_map.get(name) {
172 if !self.active_handles.contains(&handle) {
173 self.active_handles.push(handle);
174 }
175 if let Some(action) = self.actions.get_mut(handle) {
176 action.enabled = true;
177 action.weight = 1.0;
178 action.paused = false;
179 }
180 } else {
181 log::warn!("Animation not found: {name}");
182 }
183 }
184
185 pub fn stop(&mut self, name: &str) {
187 if let Some(&handle) = self.name_map.get(name) {
188 if let Some(action) = self.actions.get_mut(handle) {
189 action.stop();
190 }
191 self.active_handles.retain(|&h| h != handle);
192 }
193 }
194
195 pub fn stop_all(&mut self) {
197 for handle in &self.active_handles {
198 if let Some(action) = self.actions.get_mut(*handle) {
199 action.stop();
200 }
201 }
202 self.active_handles.clear();
203 }
204
205 pub fn drain_events(&mut self) -> Vec<FiredEvent> {
207 std::mem::take(&mut self.fired_events)
208 }
209
210 #[must_use]
212 pub fn events(&self) -> &[FiredEvent] {
213 &self.fired_events
214 }
215
216 pub fn update(&mut self, dt: f32, target: &mut dyn AnimationTarget) {
230 if !self.enabled {
231 return;
232 }
233
234 for &prev_handle in &self.animated_last_frame {
236 if let Some(rest) = target.rest_transform(prev_handle) {
237 target.set_node_position(prev_handle, rest.position);
238 target.set_node_rotation(prev_handle, rest.rotation);
239 target.set_node_scale(prev_handle, rest.scale);
240 target.mark_node_dirty(prev_handle);
241 }
242 }
243
244 let dt = dt * self.time_scale;
245 self.time += dt;
246
247 self.blend_state.clear();
249 self.fired_events.clear();
250
251 self.animated_last_frame.clear();
252
253 for &handle in &self.active_handles {
255 if let Some(action) = self.actions.get_mut(handle) {
256 let t_prev = action.time;
257 action.update(dt);
258 let t_curr = action.time;
259
260 let clip = action.clip();
261 events::collect_events(
262 &clip.events,
263 t_prev,
264 t_curr,
265 clip.duration,
266 &clip.name,
267 &mut self.fired_events,
268 );
269 }
270 }
271
272 for &handle in &self.active_handles {
274 let action = match self.actions.get_mut(handle) {
275 Some(a) if a.enabled && !a.paused && a.weight > 0.0 => a,
276 _ => continue,
277 };
278
279 let clip = action.clip().clone();
280 let weight = action.weight;
281 let time = action.time;
282 let cursors = &mut action.track_cursors;
283
284 for tb in &action.clip_binding.bindings {
285 let track = &clip.tracks[tb.track_index];
286 let cursor = &mut cursors[tb.track_index];
287 let node_handle = self.rig.bones[tb.bone_index];
288
289 match (&track.data, tb.target) {
290 (TrackData::Vector3(t), TargetPath::Translation) => {
291 let val = t.sample_with_cursor(time, cursor);
292 self.blend_state
293 .accumulate_translation(node_handle, val, weight);
294 }
295 (TrackData::Vector3(t), TargetPath::Scale) => {
296 let val = t.sample_with_cursor(time, cursor);
297 self.blend_state.accumulate_scale(node_handle, val, weight);
298 }
299 (TrackData::Quaternion(t), TargetPath::Rotation) => {
300 let val = t.sample_with_cursor(time, cursor);
301 self.blend_state
302 .accumulate_rotation(node_handle, val, weight);
303 }
304 (TrackData::MorphWeights(t), TargetPath::Weights) => {
305 t.sample_with_cursor_into(time, cursor, &mut self.morph_buffer);
306 self.blend_state.accumulate_morph_weights(
307 node_handle,
308 &self.morph_buffer,
309 weight,
310 );
311 }
312 _ => {}
313 }
314 }
315 }
316
317 for (&node_handle, props) in self.blend_state.iter_nodes() {
319 self.animated_last_frame.insert(node_handle);
320
321 let rest_transform = target.rest_transform(node_handle).unwrap_or_default();
322
323 for (t, entry) in props {
324 match (t, entry) {
325 (TargetPath::Translation, BlendEntry::Translation { value, weight }) => {
326 if *weight < 1.0 {
327 target.set_node_position(
328 node_handle,
329 rest_transform.position.lerp(*value, *weight),
330 );
331 } else {
332 target.set_node_position(node_handle, *value);
333 }
334 target.mark_node_dirty(node_handle);
335 }
336 (TargetPath::Rotation, BlendEntry::Rotation { value, weight }) => {
337 if *weight < 1.0 {
338 let corrected = if rest_transform.rotation.dot(*value) < 0.0 {
339 -*value
340 } else {
341 *value
342 };
343 target.set_node_rotation(
344 node_handle,
345 rest_transform.rotation.lerp(corrected, *weight).normalize(),
346 );
347 } else {
348 target.set_node_rotation(node_handle, *value);
349 }
350 target.mark_node_dirty(node_handle);
351 }
352 (TargetPath::Scale, BlendEntry::Scale { value, weight }) => {
353 if *weight < 1.0 {
354 target.set_node_scale(
355 node_handle,
356 rest_transform.scale.lerp(*value, *weight),
357 );
358 } else {
359 target.set_node_scale(node_handle, *value);
360 }
361 target.mark_node_dirty(node_handle);
362 }
363 (
364 TargetPath::Weights,
365 BlendEntry::MorphWeights {
366 weights,
367 total_weight,
368 },
369 ) => {
370 apply_morph_weights(target, node_handle, weights, *total_weight);
371 }
372 _ => {}
373 }
374 }
375 }
376 }
377}
378
379fn apply_morph_weights(
382 target: &mut dyn AnimationTarget,
383 node: NodeHandle,
384 weights: &[f32],
385 total_weight: f32,
386) {
387 let dst = target.morph_weights_mut(node);
388 if dst.len() < weights.len() {
389 dst.resize(weights.len(), 0.0);
390 }
391 if total_weight >= 1.0 {
392 dst[..weights.len()].copy_from_slice(weights);
393 } else {
394 for (d, &src) in dst.iter_mut().zip(weights.iter()) {
395 *d = src * total_weight;
396 }
397 }
398}
399
400pub struct ActionControl<'a> {
409 mixer: &'a mut AnimationMixer,
410 handle: ActionHandle,
411}
412
413impl ActionControl<'_> {
414 #[must_use]
416 pub fn play(self) -> Self {
417 if !self.mixer.active_handles.contains(&self.handle) {
418 self.mixer.active_handles.push(self.handle);
419 }
420 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
421 action.enabled = true;
422 action.paused = false;
423 action.weight = 1.0;
424 action.time = 0.0;
425 }
426 self
427 }
428
429 #[must_use]
430 pub fn set_loop_mode(self, mode: crate::action::LoopMode) -> Self {
431 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
432 action.loop_mode = mode;
433 }
434 self
435 }
436
437 #[must_use]
438 pub fn set_time_scale(self, scale: f32) -> Self {
439 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
440 action.time_scale = scale;
441 }
442 self
443 }
444
445 #[must_use]
446 pub fn set_weight(self, weight: f32) -> Self {
447 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
448 action.weight = weight;
449 }
450 self
451 }
452
453 #[must_use]
454 pub fn set_time(self, time: f32) -> Self {
455 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
456 action.time = time;
457 }
458 self
459 }
460
461 #[must_use]
462 pub fn resume(self) -> Self {
463 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
464 action.paused = false;
465 }
466 self
467 }
468
469 #[must_use]
470 pub fn pause(self) -> Self {
471 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
472 action.paused = true;
473 }
474 self
475 }
476
477 #[must_use]
479 pub fn stop(self) -> Self {
480 if let Some(action) = self.mixer.actions.get_mut(self.handle) {
481 action.enabled = false;
482 action.weight = 0.0;
483 }
484 self.mixer.active_handles.retain(|&h| h != self.handle);
485 self
486 }
487
488 #[must_use]
490 pub fn fade_in(self, _duration: f32) -> Self {
491 self.play()
493 }
494}
495
496impl std::ops::Deref for ActionControl<'_> {
497 type Target = AnimationAction;
498 fn deref(&self) -> &Self::Target {
499 self.mixer.actions.get(self.handle).unwrap()
500 }
501}