use std::borrow::Borrow;
use std::fmt::Debug;
use std::marker::PhantomData;
use bitvec::prelude::*;
use derivative::Derivative;
use optics::traits::{AffineFoldRef, AffineFoldMut};
use crate::curve::AnyComponent;
use crate::curve::blend::BlendMethod;
use super::{Curve, TypedCurve, Segment};
use super::animatable::Animatable;
pub trait CurveContentStatic: Send + Sync + 'static {
type Keyframe: 'static;
fn curve_content_len(&self) -> usize;
}
pub trait CurveContentBorrow<'a>: CurveContentStatic {
type KeyframeRef: Borrow<Self::Keyframe>;
fn curve_content_get(&'a self, k: usize) -> Self::KeyframeRef;
}
pub trait CurveContent: for<'a> CurveContentBorrow<'a> {}
impl<T: for<'a> CurveContentBorrow<'a>> CurveContent for T {}
impl<T: Send + Sync + 'static> CurveContentStatic for Box<[T]> {
type Keyframe = T;
fn curve_content_len(&self) -> usize { self.as_ref().len() }
}
impl<'a, T: Send + Sync + 'static> CurveContentBorrow<'a> for Box<[T]> {
type KeyframeRef = &'a T;
fn curve_content_get(&'a self, k: usize) -> &'a T { &self[k] }
}
impl<T, O> CurveContentStatic for BitBox<T, O>
where T: BitStore + Send + Sync + 'static,
O: BitOrder + Send + Sync + 'static {
type Keyframe = bool;
fn curve_content_len(&self) -> usize { self.len() }
}
impl<'a, T, O> CurveContentBorrow<'a> for BitBox<T, O>
where T: BitStore + Send + Sync + 'static,
O: BitOrder + Send + Sync + 'static {
type KeyframeRef = bool;
fn curve_content_get(&'a self, k: usize) -> bool { self[k] }
}
#[derive(Derivative)]
#[derivative(Debug(bound = "F: Debug"))]
pub struct KeyframeCurve<S, F, C> {
#[derivative(Debug = "ignore")]
_component_type: PhantomData<fn() -> S>,
field_accessor: F,
keyframe_indices: Box<[u16]>,
#[derivative(Debug = "ignore")]
keyframes: C,
}
impl<S, F, C: CurveContent> KeyframeCurve<S, F, C> {
pub fn new(field: F, indices: Box<[u16]>, keyframes: C) -> Self {
assert!(!indices.is_empty(), "never create empty curves");
assert_eq!(keyframes.curve_content_len(), indices.len(), "unaligned curve");
KeyframeCurve {
_component_type: PhantomData,
field_accessor: field,
keyframe_indices: indices,
keyframes,
}
}
fn next_keyframe(&self, frame: u16) -> usize {
self.keyframe_indices.partition_point(|&ix| ix <= frame)
}
fn last_keyframe(&self, frame: u16) -> Option<usize> {
let next = self.next_keyframe(frame);
next.checked_sub(1)
}
}
impl<S, F, C> Curve for KeyframeCurve<S, F, C>
where S: 'static, C: CurveContent<Keyframe = F::View>,
F::View: PartialEq + Animatable + Sized + Send + Sync + 'static,
F: Send + Sync + 'static
+ for<'a> AffineFoldRef<'a, S, Error = String>
+ for<'a> AffineFoldMut<'a, S, Error = String> {
type Component = S;
fn frame_count(&self) -> usize { *self.keyframe_indices.last().unwrap() as usize }
fn apply_sampled(
&self, segment: Segment, frame: f32,
blending: Option<(BlendMethod, f32)>,
output: impl AnyComponent<S>,
) -> Result<(), String> {
if let Some(val) = self.sample(segment, frame) {
if let Some((blending, progress)) = blending {
let old = self.read_field(output.component())?;
let val = F::View::interpolate(old, &val, blending.factor(progress));
self.update_field(output, val)?;
} else {
self.update_field(output, val)?;
}
}
Ok(())
}
}
impl<S, F, C> TypedCurve for KeyframeCurve<S, F, C>
where S: 'static, C: CurveContent<Keyframe = F::View>,
F::View: PartialEq + Animatable + Sized + Send + Sync + 'static,
F: Send + Sync + 'static
+ for<'a> AffineFoldRef<'a, S, Error = String>
+ for<'a> AffineFoldMut<'a, S, Error = String> {
type Value = F::View;
type FieldAccessor = F;
fn sample(&self, segment: Segment, frame: f32) -> Option<F::View> {
let frame = frame + segment.start as f32;
let (this, next, ratio) = if frame >= segment.end as f32 { let l = self.last_keyframe(segment.start)?;
let r = self.last_keyframe(segment.end)?;
(r, l, frame - segment.end as f32)
} else { let n = self.keyframe_indices.len();
let k = self.last_keyframe(frame as u16)?;
if k + 1 >= n {
(k, k, 0.0)
} else {
let elapsed = frame - self.keyframe_indices[k] as f32;
let delta = self.keyframe_indices[k + 1] - self.keyframe_indices[k];
(k, k + 1, elapsed / delta as f32)
}
};
Some(C::Keyframe::interpolate(
self.keyframes.curve_content_get(this).borrow(),
self.keyframes.curve_content_get(next).borrow(),
ratio,
))
}
fn field_accessor(&self) -> &Self::FieldAccessor {
&self.field_accessor
}
}