use ultraviolet::Slerp;
pub mod mat4 {
pub fn identity() -> [[f32; 4]; 4] {
ultraviolet::Mat4::identity().into()
}
pub fn from_translation(pos: [f32; 3]) -> [[f32; 4]; 4] {
ultraviolet::Mat4::from_translation(pos.into()).into()
}
pub fn from_scale(scale: [f32; 3]) -> [[f32; 4]; 4] {
ultraviolet::Mat4::from_nonuniform_scale(scale.into()).into()
}
pub fn from_rotation(rot: [f32; 3]) -> [[f32; 4]; 4] {
let rx = ultraviolet::Mat4::from_rotation_x(rot[0]);
let ry = ultraviolet::Mat4::from_rotation_y(rot[1]);
let rz = ultraviolet::Mat4::from_rotation_z(rot[2]);
(rx * ry * rz).into()
}
pub fn from_quat(q: [f32; 4]) -> [[f32; 4]; 4] {
let rotor = ultraviolet::Rotor3::from_quaternion_array(q);
rotor.into_matrix().into_homogeneous().into()
}
pub fn multiply(a: [[f32; 4]; 4], b: [[f32; 4]; 4]) -> [[f32; 4]; 4] {
let ma = ultraviolet::Mat4::from(a);
let mb = ultraviolet::Mat4::from(b);
(ma * mb).into()
}
pub fn look_at(eye: [f32; 3], at: [f32; 3], up: [f32; 3]) -> [[f32; 4]; 4] {
ultraviolet::Mat4::look_at(eye.into(), at.into(), up.into()).into()
}
}
pub mod projection {
pub fn perspective_degrees(fov_y_deg: f32, aspect: f32, near: f32, far: f32) -> [[f32; 4]; 4] {
let fov_y_rad = fov_y_deg.to_radians();
ultraviolet::projection::perspective_wgpu_dx(fov_y_rad, aspect, near, far).into()
}
pub fn perspective(fov_y: f32, aspect: f32, near: f32, far: f32) -> [[f32; 4]; 4] {
ultraviolet::projection::perspective_wgpu_dx(fov_y, aspect, near, far).into()
}
}
pub trait Interpolatable {
fn interpolate(self, other: Self, alpha: f32) -> Self;
}
impl Interpolatable for f32 {
fn interpolate(self, other: Self, alpha: f32) -> Self {
self + (other - self) * alpha
}
}
impl Interpolatable for [f32; 2] {
fn interpolate(self, other: Self, alpha: f32) -> Self {
[
self[0] + (other[0] - self[0]) * alpha,
self[1] + (other[1] - self[1]) * alpha,
]
}
}
impl Interpolatable for [f32; 3] {
fn interpolate(self, other: Self, alpha: f32) -> Self {
[
self[0] + (other[0] - self[0]) * alpha,
self[1] + (other[1] - self[1]) * alpha,
self[2] + (other[2] - self[2]) * alpha,
]
}
}
impl Interpolatable for [f32; 4] {
fn interpolate(self, other: Self, alpha: f32) -> Self {
[
self[0] + (other[0] - self[0]) * alpha,
self[1] + (other[1] - self[1]) * alpha,
self[2] + (other[2] - self[2]) * alpha,
self[3] + (other[3] - self[3]) * alpha,
]
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Interpolated<T> {
current: T,
previous: T,
}
#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub struct Quat(pub [f32; 4]);
impl Quat {
pub fn identity() -> Self {
Self([0.0, 0.0, 0.0, 1.0])
}
}
impl From<[f32; 4]> for Quat {
fn from(val: [f32; 4]) -> Self {
Self(val)
}
}
impl Interpolatable for Quat {
fn interpolate(self, other: Self, alpha: f32) -> Self {
let q1 = ultraviolet::Rotor3::from_quaternion_array(self.0);
let q2 = ultraviolet::Rotor3::from_quaternion_array(other.0);
let result = q1.slerp(q2, alpha);
Self(result.into_quaternion_array())
}
}
impl<T: Interpolatable + Copy> Interpolated<T> {
pub fn new(val: T) -> Self {
Self {
current: val,
previous: val,
}
}
pub fn update(&mut self, next: T) {
self.previous = self.current;
self.current = next;
}
pub fn teleport(&mut self, val: T) {
self.current = val;
self.previous = val;
}
pub fn target(&self) -> T {
self.current
}
pub fn previous(&self) -> T {
self.previous
}
pub fn value(&self, ctx: &crate::Context) -> T {
self.previous.interpolate(self.current, ctx.draw_interpolation())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_interpolation_f32() {
let mut val = Interpolated::new(0.0);
val.update(10.0);
assert_eq!(val.previous(), 0.0);
assert_eq!(val.target(), 10.0);
assert_eq!(val.previous().interpolate(val.target(), 0.5), 5.0);
}
#[test]
fn test_interpolation_v2() {
let mut val = Interpolated::new([0.0, 0.0]);
val.update([10.0, 20.0]);
assert_eq!(val.previous().interpolate(val.target(), 0.5), [5.0, 10.0]);
}
#[test]
fn test_interpolation_quat() {
let q1 = Quat::identity();
let q2 = Quat([0.0, 0.0, 0.70710677, 0.70710677]);
let mid = q1.interpolate(q2, 0.5);
assert!(mid.0[2] > 0.0 && mid.0[2] < 0.7071);
assert!(mid.0[3] > 0.7071);
}
}