use super::channels::{Channel, ProgressChannel};
use super::spec::ChannelTransition;
use crate::protocol::animatable::Animatable::Static;
use crate::protocol::{
animatable::AnimatableField, transform::Transform3d, transform::Transform3dOrigin,
units::Angle, units::Length,
};
fn origin_axis(axis: &crate::protocol::animatable::Animatable<Length>) -> Length {
axis.value().copied().unwrap_or(Length::Percent(50.0))
}
#[derive(Default)]
pub(super) struct Transform3dChannels {
perspective: Channel,
had_perspective: bool,
translate_x: Channel,
translate_y: Channel,
translate_z: Channel,
rotate_x: Channel,
rotate_y: Channel,
rotate_z: Channel,
scale: Channel,
scale_x: Channel,
scale_y: Channel,
origin_x: ProgressChannel<Length>,
origin_y: ProgressChannel<Length>,
}
impl Transform3dChannels {
pub(super) fn in_flight(&self) -> bool {
[
&self.perspective,
&self.translate_x,
&self.translate_y,
&self.translate_z,
&self.rotate_x,
&self.rotate_y,
&self.rotate_z,
&self.scale,
&self.scale_x,
&self.scale_y,
]
.iter()
.any(|c| c.runner.is_some())
|| self.origin_x.runner.is_some()
|| self.origin_y.runner.is_some()
}
pub(super) fn seed_from(&mut self, other: &Self) {
self.perspective.init(other.perspective.current);
self.had_perspective = other.had_perspective;
self.translate_x.init(other.translate_x.current);
self.translate_y.init(other.translate_y.current);
self.translate_z.init(other.translate_z.current);
self.rotate_x.init(other.rotate_x.current);
self.rotate_y.init(other.rotate_y.current);
self.rotate_z.init(other.rotate_z.current);
self.scale.init(other.scale.current);
self.scale_x.init(other.scale_x.current);
self.scale_y.init(other.scale_y.current);
self.origin_x.init(other.origin_x.current);
self.origin_y.init(other.origin_y.current);
}
pub(super) fn init(&mut self, t: &Transform3d) {
let origin = t.origin.clone().unwrap_or_default();
macro_rules! seed {
($prop:tt, (t3d $f:ident num $d:tt)) => {
self.$f.init(t.$f.static_val().unwrap_or($d));
};
($prop:tt, (t3d $f:ident angle)) => {
self.$f
.init(t.$f.static_val().unwrap_or_default().radians());
};
($prop:tt, $other:tt) => {};
}
macro_rules! walk {
($(($prop:tt, $acc:tt, $write:tt, $stage:ident, $park:ident),)*) => {
$(seed!($prop, $acc);)*
};
}
crate::animations::props::with_animatable_props!(walk);
self.had_perspective = t.perspective.is_some();
self.origin_x.init(origin_axis(&origin.x));
self.origin_y.init(origin_axis(&origin.y));
}
pub(super) fn drive(
&mut self,
target: &Transform3d,
spec: Option<&ChannelTransition>,
dt: f32,
) -> Transform3d {
let perspective = match (self.had_perspective, target.perspective.static_val()) {
(true, Some(d)) => Some(Static(self.perspective.drive(d, spec, dt))),
(false, Some(d)) => {
self.perspective.init(d);
Some(Static(d))
}
(_, None) => None,
};
self.had_perspective = target.perspective.is_some();
let origin = target.origin.clone().unwrap_or_default();
let mut out = Transform3d {
perspective,
origin: Some(Transform3dOrigin {
x: Static(self.origin_x.drive(origin_axis(&origin.x), spec, dt)),
y: Static(self.origin_y.drive(origin_axis(&origin.y), spec, dt)),
}),
..Default::default()
};
macro_rules! drive_field {
($prop:tt, (t3d perspective num $d:tt)) => {};
($prop:tt, (t3d $f:ident num $d:tt)) => {
out.$f = Some(Static(self.$f.drive(
target.$f.static_val().unwrap_or($d),
spec,
dt,
)));
};
($prop:tt, (t3d $f:ident angle)) => {
out.$f = Some(Static(Angle::from_radians(self.$f.drive(
target.$f.static_val().unwrap_or_default().radians(),
spec,
dt,
))));
};
($prop:tt, $other:tt) => {};
}
macro_rules! walk {
($(($prop:tt, $acc:tt, $write:tt, $stage:ident, $park:ident),)*) => {
$(drive_field!($prop, $acc);)*
};
}
crate::animations::props::with_animatable_props!(walk);
out
}
}