diff options
feat: in theory this "works"
| -rw-r--r-- | src/interpolation.rs | 115 | ||||
| -rw-r--r-- | src/main.rs | 1 | 
2 files changed, 112 insertions, 4 deletions
| diff --git a/src/interpolation.rs b/src/interpolation.rs index de6b6df..d088bf8 100644 --- a/src/interpolation.rs +++ b/src/interpolation.rs @@ -1,4 +1,17 @@ -use std::ops::{Add, Mul, Sub}; +// NOTE: This entire file would need to be reworked to handle functions like bezier curves/any other fn involving multiple points. +//       Someone should do this at some point. +// +//       This likely would only be slightly breaking; ie the most commonly used portions of AnimationTrack would remain in-tact +//       however, the internals of a KeyFrame would change immensely and be (more or less) impossible to keep + +use std::ops::{Add, Index, Mul, Sub}; + +// For when RFC1733 finally passes +// trait AcceptableValueType<ValueType> = PartialOrd +//   + Copys +//   + Add<Output = ValueType> +//   + Sub<Output = ValueType> +//   + Mul<f64, Output = ValueType>;  pub fn raw_lerp<T>(a: T, b: T, t: f64) -> T  where @@ -7,11 +20,13 @@ where    a + (b - a) * t  } +#[derive(Clone, Copy)]  pub enum TimingFunction {    Lerp,  } +#[derive(Clone, Copy, PartialEq, PartialOrd)] +// We could make a TimeType generic (I initially did), however it's safe to assume we use a 64-bit float for this  pub struct KeyFrame<ValueType> { -  // We could make a TimeType generic (I initially did), however it's safe to assume we use a 64-bit float for this    pub time: f64,    pub val: ValueType,  } @@ -28,7 +43,9 @@ impl<        + Mul<f64, Output = ValueType>,    > KeyFrame<ValueType>  { -  /** Simply passes the data to the timing function involved. Does not do bounding. */ +  /** +  Simply passes the data to the timing function involved. Does not do bounding. +  */    pub fn raw_value_at(      from: &KeyFrame<ValueType>,      to: &KeyFrame<ValueType>, @@ -48,3 +65,95 @@ impl<      }    }  } + +#[derive(Clone)] +pub struct AnimationTrack<ValueType> { +  pub keyframes: Vec<KeyFrame<ValueType>>, +  pub loop_count: u32, +} +impl<ValueType: Copy> AnimationTrack<ValueType> { +  fn get_sorted_keyframes(&self) -> Vec<KeyFrame<ValueType>> { +    let mut kf = self.keyframes.clone(); +    kf.sort_by(|a, b| a.time.total_cmp(&b.time)); +    kf +  } +  fn get_first_last(&self) -> Option<(KeyFrame<ValueType>, KeyFrame<ValueType>)> { +    let okf = self.get_sorted_keyframes(); +    if okf.len() == 0 { +      None +    } else { +      Some((*okf.first().unwrap(), *okf.last().unwrap())) +    } +  } +  fn length(fl: (KeyFrame<ValueType>, KeyFrame<ValueType>)) -> f64 { +    fl.1.time - fl.0.time +  } +} +impl< +    ValueType: PartialOrd +      + Copy +      + Add<Output = ValueType> +      + Sub<Output = ValueType> +      + Mul<f64, Output = ValueType>, +  > AnimationTrack<ValueType> +{ +  /** Get the 2 keyframes surrounding the current position in time. */ +  fn get_current_keyframes( +    &self, +    // We have the user pass this, as to prevent needing to constantly re-calculate it. +    sorted_keyframes: Vec<KeyFrame<ValueType>>, +    time: f64, +  ) -> Option<(KeyFrame<ValueType>, KeyFrame<ValueType>)> { +    // TODO: maybe refactor the internals of this to be faster +    let idx = { +      let mut idx = 0; +      let mut found = false; +      for f in &sorted_keyframes { +        if f.time > time { +          found = true; +          break; +        } else { +          idx += 1; +        } +      } +      if found { +        Some(idx) +      } else { +        None +      } +    }; +    match idx { +      None => None, +      Some(idx) => { +        // If it's the last item, we don't have a 2nd +        if idx + 1 == sorted_keyframes.len() { +          None +        } else { +          Some(( +            *sorted_keyframes.index(idx), +            *sorted_keyframes.index(idx + 1), +          )) +        } +      } +    } +  } +  /** Gets the current value */ +  pub fn get_current_value( +    &self, +    // We have the user pass this, as to prevent needing to constantly re-calculate it. +    sorted_keyframes: Vec<KeyFrame<ValueType>>, +    time: f64, +    timing_function: TimingFunction, +  ) -> Option<ValueType> { +    let frames = self.get_current_keyframes(sorted_keyframes, time); +    match frames { +      Some(frames) => Some(KeyFrame::raw_value_at( +        &frames.0, +        &frames.1, +        time, +        timing_function, +      )), +      None => None, +    } +  } +} diff --git a/src/main.rs b/src/main.rs index f9c52f9..c7a7606 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,6 @@ pub fn main() {    canvas.present();    let mut event_pump = sdl_context.event_pump().unwrap(); -  // amount to incr sin_offset by per frame    let start_time = SystemTime::now();    'running: loop {      let time = SystemTime::now() |