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 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, $kind:ident, $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, $kind:ident, $acc:tt, $write:tt, $stage:ident, $park:ident),)*) => {
$(drive_field!($prop, $acc);)*
};
}
crate::animations::props::with_animatable_props!(walk);
out
}
}