diff --git a/src/animation.rs b/src/animation.rs index e3078b2..c84c025 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -1,29 +1,30 @@ -use embassy_time::{Duration, Timer}; -use figments::surface::Surface; +use embassy_time::{Duration, Instant, Timer}; +use esp_rtos::CurrentThreadHandle; +use figments::{liber8tion::interpolate::Fract8, surface::Surface}; use figments_render::output::Brightness; -use core::{fmt::Debug, ops::{Deref, DerefMut}}; +use core::{fmt::Debug, mem::MaybeUninit, ops::{Deref, DerefMut}}; use log::*; use crate::graphics::display::DisplayControls; #[derive(Default, Debug, Clone, Copy)] -pub struct Animation { - from: Option, - to: Option, +pub struct Animation { + from: Option, + to: Option, duration: Duration } -pub trait AnimationActor { - fn get_opacity(&self) -> u8; - fn set_opacity(&mut self, opacity: u8); +pub trait AnimationActor { + fn get_value(&self) -> T; + fn set_value(&mut self, value: T); } -impl AnimationActor for S { - fn get_opacity(&self) -> u8 { - 0 +impl AnimationActor for S { + fn get_value(&self) -> Fract8 { + unimplemented!() } - fn set_opacity(&mut self, opacity: u8) { + fn set_value(&mut self, opacity: Fract8) { self.set_opacity(opacity); } } @@ -31,28 +32,48 @@ impl AnimationActor for S { #[derive(Debug)] pub struct AnimDisplay<'a>(pub &'a mut DisplayControls); -impl<'a> AnimationActor for AnimDisplay<'a> { - fn get_opacity(&self) -> u8 { +impl<'a> AnimationActor for AnimDisplay<'a> { + fn get_value(&self) -> Fract8 { self.0.brightness() } - fn set_opacity(&mut self, opacity: u8) { + fn set_value(&mut self, opacity: Fract8) { self.0.set_brightness(opacity); } } -impl AnimationActor for AnimatedSurface { - fn get_opacity(&self) -> u8 { +impl AnimationActor for AnimatedSurface { + fn get_value(&self) -> Fract8 { self.opacity } - fn set_opacity(&mut self, opacity: u8) { + fn set_value(&mut self, opacity: Fract8) { self.surface.set_opacity(opacity); self.opacity = opacity; } } -impl Animation { +struct Slot<'a, T> { + from: T, + to: T, + cur_step: T, + step_time: Duration, + next_update: Instant, + target: &'a mut dyn AnimationActor +} + +impl<'a, T: Debug> core::fmt::Debug for Slot<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Slot") + .field("from", &self.from) + .field("to", &self.to) + .field("cur_step", &self.cur_step) + .field("step_time", &self.step_time) + .field("next_update", &self.next_update).finish() + } +} + +impl Animation { pub const fn new() -> Self { Self { from: None, @@ -60,61 +81,111 @@ impl Animation { duration: Duration::from_ticks(0) } } - pub const fn from(self, from: u8) -> Self { + + pub const fn from(self, from: Fract8) -> Self { Self { from: Some(from), - to: self.to, - duration: self.duration + ..self } } - pub const fn to(self, to: u8) -> Self { + pub const fn to(self, to: Fract8) -> Self { Self { - from: self.from, to: Some(to), - duration: self.duration + ..self } } pub const fn duration(self, duration: Duration) -> Self { Self { - from: self.from, - to: self.to, - duration + duration, + ..self } } +} - pub async fn apply(&self, sfc: &mut S) { - let from = if let Some(val) = self.from { - val - } else { - sfc.get_opacity() - }; - let to = if let Some(val) = self.to { - val - } else { - sfc.get_opacity() - }; - let steps = from.abs_diff(to); - if steps == 0 { - return; - } - let step_time = self.duration / steps.into(); - trace!("fade={self:?} steps={steps} time={step_time}"); - if from > to { - let range = (to..=from).rev(); - for opacity in range { - sfc.set_opacity(opacity); - Timer::after(step_time).await; - } - } else { - let range = from..=to; +impl Animation { + pub async fn apply(&self, actors: [&mut dyn AnimationActor; ACTOR_COUNT]) { - for opacity in range { - sfc.set_opacity(opacity); - Timer::after(step_time).await; + let mut now = Instant::now(); + trace!("start now={now:?} ACTOR_COUNT={ACTOR_COUNT}"); + + let mut actors = actors.into_iter(); + let mut animators: [Slot; ACTOR_COUNT] = core::array::from_fn(|_| { + let target = actors.next().unwrap(); + let from = if let Some(val) = self.from { + val + } else { + target.get_value() + }; + let to = if let Some(val) = self.to { + val + } else { + target.get_value() + }; + let steps = to.abs_diff(from); + + let step_time = if steps == Fract8::MIN { + Duration::from_ticks(0) + } else { + (self.duration / steps.to_raw().into()).max(Duration::from_millis(1)) + }; + Slot { + from, + to, + cur_step: from, + step_time, + next_update: now, + target } + }); + + trace!("animators={animators:?}"); + + loop { + // Find the next shortest delay + let mut next_keyframe_time = animators[0].next_update; + let mut finished = false; + for animator in &mut animators { + if animator.step_time.as_ticks() == 0 { + continue; + } + if animator.next_update <= now { + animator.next_update += animator.step_time; + animator.cur_step = if animator.to > animator.from { + animator.cur_step + Fract8::from_raw(1) + } else { + animator.cur_step - Fract8::from_raw(1) + }; + + if (animator.to > animator.from && animator.cur_step >= animator.to) || + (animator.to <= animator.from && animator.cur_step <= animator.to) { + finished = true; + } + + /*if animator.cur_step == animator.from || animator.cur_step == animator.to { + finished = true; + }*/ + + animator.target.set_value(animator.cur_step); + } + + if next_keyframe_time <= now || animator.next_update < next_keyframe_time { + next_keyframe_time = animator.next_update; + } + } + + if finished { + break; + } + + let keyframe_delay = next_keyframe_time - now; + trace!("delay {keyframe_delay:?}"); + Timer::after(keyframe_delay).await; + now += keyframe_delay; } + + trace!("finished animators={animators:?}"); } } @@ -122,7 +193,7 @@ impl Animation { pub struct AnimatedSurface { surface: S, is_on: bool, - opacity: u8 + opacity: Fract8 } impl Deref for AnimatedSurface { @@ -145,7 +216,7 @@ impl From for AnimatedSurface { AnimatedSurface { surface, is_on: false, - opacity: 255 + opacity: Fract8::MAX } } } @@ -155,11 +226,11 @@ impl AnimatedSurface { if self.is_on != is_on { let anim = if is_on { self.surface.set_visible(true); - Animation::default().duration(Duration::from_secs(1)).from(0).to(255) + Animation::default().duration(Duration::from_secs(1)).from(Fract8::MIN).to(Fract8::MAX) } else { - Animation::default().duration(Duration::from_secs(1)).from(255).to(0) + Animation::default().duration(Duration::from_secs(1)).from(Fract8::MAX).to(Fract8::MIN) }; - anim.apply(&mut self.surface).await; + anim.apply([&mut self.surface]).await; self.is_on = true; if !is_on { self.surface.set_visible(false);