use crate::Frame;
use nalgebra::{Point3, RealField, Unit, UnitQuaternion, Vector3};
use simba::scalar::SubsetOf;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Delta<N: Copy + RealField> {
Frame,
First {
pitch: N,
yaw: N,
yaw_axis: Unit<Vector3<N>>,
},
Track {
vec: Vector3<N>,
},
Orbit {
rot: UnitQuaternion<N>,
pos: Point3<N>,
},
Slide {
vec: Vector3<N>,
},
Scale {
rat: N,
pos: Point3<N>,
},
}
impl<N: Copy + RealField> Delta<N> {
#[must_use]
pub fn transform(&self, frame: &Frame<N>) -> Frame<N> {
let mut frame = *frame;
match self {
Self::Frame => {}
Self::First {
pitch,
yaw,
ref yaw_axis,
} => frame.look_around(*pitch, *yaw, yaw_axis),
Self::Track { vec } => frame.set_target(frame.target() + vec),
Self::Orbit { rot, pos } => frame.local_orbit_around(rot, pos),
Self::Slide { vec } => frame.local_slide(vec),
Self::Scale { rat, pos } => frame.local_scale_around(*rat, pos),
}
frame
}
#[must_use]
pub fn inverse(self) -> Self {
match self {
Self::Frame => Self::Frame,
Self::First {
pitch,
yaw,
yaw_axis,
} => Self::First {
pitch: -pitch,
yaw: -yaw,
yaw_axis,
},
Self::Track { vec } => Self::Track { vec: -vec },
Self::Orbit { rot, pos } => Self::Orbit {
rot: rot.inverse(),
pos,
},
Self::Slide { vec } => Self::Slide { vec: -vec },
Self::Scale { rat, pos } => Self::Scale {
rat: N::one() + N::one() - rat,
pos,
},
}
}
#[must_use]
pub fn lerp_slerp(&self, t: N) -> Self {
match *self {
Self::Frame => Self::Frame,
Self::First {
pitch,
yaw,
yaw_axis,
} => Self::First {
pitch: pitch * t,
yaw: yaw * t,
yaw_axis,
},
Self::Track { vec } => Self::Track { vec: vec * t },
Self::Orbit { rot, pos } => Self::Orbit {
rot: rot.powf(t),
pos,
},
Self::Slide { vec } => Self::Slide { vec: vec * t },
Self::Scale { rat, pos } => Self::Scale {
rat: (rat - N::one()) * t + N::one(),
pos,
},
}
}
#[must_use]
pub fn cast<M: Copy + RealField>(self) -> Delta<M>
where
N: SubsetOf<M>,
{
match self {
Self::Frame => Delta::Frame,
Self::First {
pitch,
yaw,
yaw_axis,
} => Delta::First {
pitch: pitch.to_superset(),
yaw: yaw.to_superset(),
yaw_axis: yaw_axis.cast(),
},
Self::Track { vec } => Delta::Track { vec: vec.cast() },
Self::Orbit { rot, pos } => Delta::Orbit {
rot: rot.cast(),
pos: pos.cast(),
},
Self::Slide { vec } => Delta::Slide { vec: vec.cast() },
Self::Scale { rat, pos } => Delta::Scale {
rat: rat.to_superset(),
pos: pos.cast(),
},
}
}
}
impl<N: Copy + RealField> Default for Delta<N> {
fn default() -> Self {
Self::Frame
}
}
#[cfg(feature = "rkyv")]
impl<N: Copy + RealField> rkyv::Archive for Delta<N> {
type Archived = Self;
type Resolver = ();
#[inline]
#[allow(unsafe_code)]
unsafe fn resolve(&self, _: usize, (): Self::Resolver, out: *mut Self::Archived) {
out.write(rkyv::to_archived!(*self as Self));
}
}
#[cfg(feature = "rkyv")]
impl<Ser: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Serialize<Ser> for Delta<N> {
#[inline]
fn serialize(&self, _: &mut Ser) -> Result<Self::Resolver, Ser::Error> {
Ok(())
}
}
#[cfg(feature = "rkyv")]
impl<De: rkyv::Fallible + ?Sized, N: Copy + RealField> rkyv::Deserialize<Self, De> for Delta<N> {
#[inline]
fn deserialize(&self, _: &mut De) -> Result<Self, De::Error> {
Ok(rkyv::from_archived!(*self))
}
}