use cgmath::{BaseFloat, InnerSpace};
use serde::de::DeserializeOwned;
use serde_json::{Error as JsonError, from_reader};
use std::error::Error;
use std::fmt;
use std::f32::consts;
use std::fs::File;
use std::ops::{Add, Div, Mul, Sub};
use std::path::PathBuf;
use linear::{Scale, Quat, V2, V3, V4};
use sys::res::{FSKey, Load, Loaded, Storage};
use sys::res::helpers::{TyDesc, load_with};
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct Key<T> {
pub t: f32,
pub value: T,
#[serde(default)]
pub interpolation: Interpolation
}
impl<T> Key<T> {
pub fn new(t: f32, value: T, interpolation: Interpolation) -> Self {
Key {
t: t,
value: value,
interpolation: interpolation
}
}
}
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub enum Interpolation {
#[serde(rename = "step")]
Step(f32),
#[serde(rename = "linear")]
Linear,
#[serde(rename = "cosine")]
Cosine,
#[serde(rename = "catmull_rom")]
CatmullRom
}
impl Default for Interpolation {
fn default() -> Self {
Interpolation::Linear
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Spline<T>(Vec<Key<T>>);
impl<T> Spline<T> {
pub fn from_keys(mut keys: Vec<Key<T>>) -> Self {
keys.sort_by(|k0, k1| k0.t.partial_cmp(&k1.t).unwrap());
Spline(keys)
}
pub fn keys(&self) -> &[Key<T>] {
&self.0
}
pub fn sample(&self, t: f32) -> Option<T> where T: Interpolate {
let keys = &self.0;
let i = search_lower_cp(keys, t);
let i = match i {
Some(i) => i,
None => return None
};
let cp0 = &keys[i];
match cp0.interpolation {
Interpolation::Step(threshold) => {
let cp1 = &keys[i+1];
let nt = normalize_time(t, cp0, cp1);
Some(if nt < threshold { cp0.value } else { cp1.value })
},
Interpolation::Linear => {
let cp1 = &keys[i+1];
let nt = normalize_time(t, cp0, cp1);
Some(Interpolate::lerp(cp0.value, cp1.value, nt))
},
Interpolation::Cosine => {
let cp1 = &keys[i+1];
let nt = normalize_time(t, cp0, cp1);
let cos_nt = (1. - f32::cos(nt * consts::PI)) * 0.5;
Some(Interpolate::lerp(cp0.value, cp1.value, cos_nt))
},
Interpolation::CatmullRom => {
if i == 0 || i >= keys.len() - 2 {
None
} else {
let cp1 = &keys[i+1];
let cpm0 = &keys[i-1];
let cpm1 = &keys[i+2];
let nt = normalize_time(t, cp0, cp1);
Some(Interpolate::cubic_hermite((cpm0.value, cpm0.t), (cp0.value, cp0.t), (cp1.value, cp1.t), (cpm1.value, cpm1.t), nt))
}
}
}
}
pub fn clamped_sample(&self, t: f32) -> T where T: Interpolate {
let first = self.0.first().unwrap();
let last = self.0.last().unwrap();
if t <= first.t {
return first.value;
} else if t >= last.t {
return last.value;
}
self.sample(t).unwrap()
}
}
impl<T> TyDesc for Spline<T> {
const TY_DESC: &'static str = "spline";
}
impl<C, T> Load<C> for Spline<T> where T: 'static + SplineDeserializerAdapter {
type Key = FSKey;
type Error = SplineError;
fn load(key: Self::Key, _: &mut Storage<C>, _: &mut C) -> Result<Loaded<Self>, Self::Error> {
let path = key.as_path();
load_with::<Self, _, _, _>(path, move || {
let file = File::open(path).map_err(|_| SplineError::FileNotFound(path.to_owned()))?;
let keys: Vec<Key<T::Deserialized>> = from_reader(file).map_err(SplineError::ParseFailed)?;
Ok(Spline::from_keys(keys.into_iter().map(|key|
Key::new(key.t, T::from_deserialized(key.value), key.interpolation)
).collect()).into())
})
}
impl_reload_passthrough!(C);
}
#[derive(Debug)]
pub enum SplineError {
FileNotFound(PathBuf),
ParseFailed(JsonError)
}
impl fmt::Display for SplineError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.write_str(self.description())
}
}
impl Error for SplineError {
fn description(&self) -> &str {
match *self {
SplineError::FileNotFound(_) => "file not found",
SplineError::ParseFailed(_) => "parse failed"
}
}
fn cause(&self) -> Option<&Error> {
match *self {
SplineError::ParseFailed(ref e) => Some(e),
_ => None
}
}
}
pub trait SplineDeserializerAdapter {
type Deserialized: DeserializeOwned;
fn from_deserialized(de: Self::Deserialized) -> Self;
}
impl SplineDeserializerAdapter for f32 {
type Deserialized = Self;
fn from_deserialized(de: Self::Deserialized) -> Self {
de
}
}
impl<T> SplineDeserializerAdapter for V2<T> where T: BaseFloat + DeserializeOwned {
type Deserialized = [T; 2];
fn from_deserialized(de: Self::Deserialized) -> Self {
de.into()
}
}
impl<T> SplineDeserializerAdapter for V3<T> where T: BaseFloat + DeserializeOwned {
type Deserialized = [T; 3];
fn from_deserialized(de: Self::Deserialized) -> Self {
de.into()
}
}
impl<T> SplineDeserializerAdapter for V4<T> where T: BaseFloat + DeserializeOwned {
type Deserialized = [T; 4];
fn from_deserialized(de: Self::Deserialized) -> Self {
de.into()
}
}
impl<T> SplineDeserializerAdapter for Quat<T> where T: BaseFloat + DeserializeOwned {
type Deserialized = [T; 4];
fn from_deserialized(de: Self::Deserialized) -> Self {
de.into()
}
}
impl SplineDeserializerAdapter for Scale {
type Deserialized = [f32; 3];
fn from_deserialized(de: Self::Deserialized) -> Self {
de.into()
}
}
pub struct SplineIterator<'a, T> where T: 'a {
anim_param: &'a Spline<T>,
i: usize
}
impl<'a, T> Iterator for SplineIterator<'a, T> {
type Item = &'a Key<T>;
fn next(&mut self) -> Option<Self::Item> {
let r = self.anim_param.0.get(self.i);
if let Some(_) = r {
self.i += 1;
}
r
}
}
impl<'a, T> IntoIterator for &'a Spline<T> {
type Item = &'a Key<T>;
type IntoIter = SplineIterator<'a, T>;
fn into_iter(self) -> Self::IntoIter {
SplineIterator {
anim_param: self,
i: 0
}
}
}
pub trait Interpolate: Copy {
fn lerp(a: Self, b: Self, t: f32) -> Self;
fn cubic_hermite(_: (Self, f32), a: (Self, f32), b: (Self, f32), _: (Self, f32), t: f32) -> Self {
Self::lerp(a.0, b.0, t)
}
}
impl Interpolate for f32 {
fn lerp(a: Self, b: Self, t: f32) -> Self {
a * (1. - t) + b * t
}
fn cubic_hermite(x: (Self, f32), a: (Self, f32), b: (Self, f32), y: (Self, f32), t: f32) -> Self {
cubic_hermite(x, a, b, y, t)
}
}
impl Interpolate for V2<f32> {
fn lerp(a: Self, b: Self, t: f32) -> Self {
a.lerp(b, t)
}
fn cubic_hermite(x: (Self, f32), a: (Self, f32), b: (Self, f32), y: (Self, f32), t: f32) -> Self {
cubic_hermite(x, a, b, y, t)
}
}
impl Interpolate for V3<f32> {
fn lerp(a: Self, b: Self, t: f32) -> Self {
a.lerp(b, t)
}
fn cubic_hermite(x: (Self, f32), a: (Self, f32), b: (Self, f32), y: (Self, f32), t: f32) -> Self {
cubic_hermite(x, a, b, y, t)
}
}
impl Interpolate for V4<f32> {
fn lerp(a: Self, b: Self, t: f32) -> Self {
a.lerp(b, t)
}
fn cubic_hermite(x: (Self, f32), a: (Self, f32), b: (Self, f32), y: (Self, f32), t: f32) -> Self {
cubic_hermite(x, a, b, y, t)
}
}
impl Interpolate for Quat<f32> {
fn lerp(a: Self, b: Self, t: f32) -> Self {
a.nlerp(b, t)
}
}
impl Interpolate for Scale {
fn lerp(a: Self, b: Self, t: f32) -> Self {
let av = V3::new(a.x, a.y, a.z);
let bv = V3::new(b.x, b.y, b.z);
let r = av.lerp(bv, t);
Scale::new(r.x, r.y, r.z)
}
}
pub fn cubic_hermite<T>(x: (T, f32), a: (T, f32), b: (T, f32), y: (T, f32), t: f32) -> T
where T: Copy + Add<Output = T> + Sub<Output = T> + Mul<f32, Output = T> + Div<f32, Output = T> {
let t2 = t * t;
let t3 = t2 * t;
let two_t3 = 2. * t3;
let three_t2 = 3. * t2;
let m0 = (b.0 - x.0) / (b.1 - x.1);
let m1 = (y.0 - a.0) / (y.1 - a.1);
a.0 * (two_t3 - three_t2 + 1.) + m0 * (t3 - 2. * t2 + t) + b.0 * (-two_t3 + three_t2) + m1 * (t3 - t2)
}
pub fn normalize_time<T>(t: f32, cp: &Key<T>, cp1: &Key<T>) -> f32 {
(t - cp.t) / (cp1.t - cp.t)
}
fn search_lower_cp<T>(cps: &[Key<T>], t: f32) -> Option<usize> {
let mut i = 0;
let len = cps.len();
if len < 2 {
return None;
}
loop {
let cp = &cps[i];
let cp1 = &cps[i+1];
if t >= cp1.t {
if i >= len - 2 {
return None;
}
i += 1;
} else if t < cp.t {
if i == 0 {
return None;
}
i -= 1;
} else {
break; }
}
Some(i)
}