175 lines
4.4 KiB
Rust
175 lines
4.4 KiB
Rust
use utilities::prelude::cgmath::{InnerSpace, Quaternion, Vector3};
|
|
|
|
use std::time::Duration;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Translation {
|
|
time: Duration,
|
|
translation: Vector3<f32>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Rotation {
|
|
time: Duration,
|
|
rotation: Quaternion<f32>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Scale {
|
|
time: Duration,
|
|
scale: Vector3<f32>,
|
|
}
|
|
|
|
pub(crate) trait LinearInterpolation {
|
|
type Inner;
|
|
|
|
fn new(time: Duration, value: Self::Inner) -> Self;
|
|
|
|
fn time(&self) -> Duration;
|
|
fn linear_interpolation(&self, other: &Self, now: Duration) -> Self;
|
|
fn to_inner(&self) -> Self::Inner;
|
|
fn almost_equal(&self, other: &Self) -> bool;
|
|
}
|
|
|
|
impl LinearInterpolation for Translation {
|
|
type Inner = Vector3<f32>;
|
|
|
|
fn new(time: Duration, translation: Vector3<f32>) -> Self {
|
|
Translation { time, translation }
|
|
}
|
|
|
|
fn time(&self) -> Duration {
|
|
self.time
|
|
}
|
|
|
|
fn linear_interpolation(&self, other: &Self, now: Duration) -> Self {
|
|
debug_assert!(self.time > other.time);
|
|
|
|
let interpolation_value = (now.as_secs_f32() - other.time.as_secs_f32())
|
|
/ (self.time.as_secs_f32() - other.time.as_secs_f32());
|
|
|
|
let translation =
|
|
other.translation + interpolation_value * (self.translation - other.translation);
|
|
|
|
Translation {
|
|
time: now,
|
|
translation,
|
|
}
|
|
}
|
|
|
|
fn to_inner(&self) -> Vector3<f32> {
|
|
self.translation
|
|
}
|
|
|
|
fn almost_equal(&self, other: &Self) -> bool {
|
|
almost_equal_f32(self.translation.x, other.translation.x)
|
|
&& almost_equal_f32(self.translation.y, other.translation.y)
|
|
&& almost_equal_f32(self.translation.z, other.translation.z)
|
|
}
|
|
}
|
|
|
|
impl LinearInterpolation for Rotation {
|
|
type Inner = Quaternion<f32>;
|
|
|
|
fn new(time: Duration, rotation: Quaternion<f32>) -> Self {
|
|
Rotation { time, rotation }
|
|
}
|
|
|
|
fn time(&self) -> Duration {
|
|
self.time
|
|
}
|
|
|
|
fn linear_interpolation(&self, other: &Self, now: Duration) -> Self {
|
|
debug_assert!(self.time > other.time);
|
|
|
|
let interpolation_value = (now.as_secs_f32() - other.time.as_secs_f32())
|
|
/ (self.time.as_secs_f32() - other.time.as_secs_f32());
|
|
|
|
let norm_me = self.rotation.normalize();
|
|
let norm_other = other.rotation.normalize();
|
|
|
|
let rotation = slerp(norm_other, norm_me, interpolation_value);
|
|
|
|
Rotation {
|
|
time: now,
|
|
rotation,
|
|
}
|
|
}
|
|
|
|
fn to_inner(&self) -> Quaternion<f32> {
|
|
self.rotation
|
|
}
|
|
|
|
fn almost_equal(&self, other: &Self) -> bool {
|
|
almost_equal_f32(self.rotation.s, other.rotation.s)
|
|
&& almost_equal_f32(self.rotation.v.x, other.rotation.v.x)
|
|
&& almost_equal_f32(self.rotation.v.y, other.rotation.v.y)
|
|
&& almost_equal_f32(self.rotation.v.z, other.rotation.v.z)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn slerp(p: Quaternion<f32>, q: Quaternion<f32>, t: f32) -> Quaternion<f32> {
|
|
let dot = p.dot(q);
|
|
|
|
if dot < 0.0 {
|
|
return slerp(-1.0 * p, q, t);
|
|
}
|
|
|
|
let angle = dot.acos();
|
|
let sin = angle.sin();
|
|
|
|
if almost_equal_f32(sin, 0.0) {
|
|
return p;
|
|
}
|
|
|
|
let first = p * ((1.0 - t) * angle).sin();
|
|
let second = q * (t * angle).sin();
|
|
|
|
(first + second) / sin
|
|
}
|
|
|
|
impl LinearInterpolation for Scale {
|
|
type Inner = Vector3<f32>;
|
|
|
|
fn new(time: Duration, scale: Vector3<f32>) -> Self {
|
|
Scale { time, scale }
|
|
}
|
|
|
|
fn time(&self) -> Duration {
|
|
self.time
|
|
}
|
|
|
|
fn linear_interpolation(&self, other: &Self, now: Duration) -> Self {
|
|
debug_assert!(self.time > other.time);
|
|
|
|
let interpolation_value = (now.as_secs_f32() - other.time.as_secs_f32())
|
|
/ (self.time.as_secs_f32() - other.time.as_secs_f32());
|
|
|
|
let scale = other.scale + interpolation_value * (self.scale - other.scale);
|
|
|
|
Scale { time: now, scale }
|
|
}
|
|
|
|
fn to_inner(&self) -> Vector3<f32> {
|
|
self.scale
|
|
}
|
|
|
|
fn almost_equal(&self, other: &Self) -> bool {
|
|
almost_equal_f32(self.scale.x, other.scale.x)
|
|
&& almost_equal_f32(self.scale.y, other.scale.y)
|
|
&& almost_equal_f32(self.scale.z, other.scale.z)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn almost_equal_f32(f1: f32, f2: f32) -> bool {
|
|
(f1 - f2).abs() < 0.000001
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum Transform {
|
|
Translation(Vector3<f32>),
|
|
Rotation(Quaternion<f32>),
|
|
Scale(Vector3<f32>),
|
|
}
|