sm64pc/gamebridge/src/au.rs

100 lines
2.4 KiB
Rust

#[derive(Copy, Clone)]
pub(crate) struct Lerper {
extended_tick: u64,
lerp_time: f64,
goal: i64,
pub(crate) scalar: i64,
max: i64,
min: i64,
}
impl Lerper {
pub(crate) fn init(lerp_time: f64, max: i64, min: i64, goal: i64) -> Lerper {
Lerper {
extended_tick: 0,
lerp_time: lerp_time,
goal: goal,
scalar: 0, // I hope to GOD that 0 is the resting point
max: max,
min: min,
}
}
pub(crate) fn add(&mut self, new_scalar: i64) {
self.scalar += new_scalar;
}
pub(crate) fn update(&mut self, new_scalar: i64) {
self.scalar = new_scalar;
}
pub(crate) fn apply(&mut self, now: u64) -> i64 {
let scalar = self.scalar;
self.scalar = match scalar {
_ if scalar == self.goal => self.goal,
_ if scalar >= self.max => {
self.extended_tick = now;
scalar - 1
}
_ if scalar <= self.min => {
self.extended_tick = now;
scalar + 1
}
_ => {
let t = (now - self.extended_tick) as f64 / self.lerp_time;
lerp(self.scalar, 0, t)
}
};
if self.scalar >= self.max {
return self.max;
}
if self.scalar <= self.min {
return self.min;
}
self.scalar
}
pub(crate) fn pressed(&mut self, threshold: i64) -> bool {
if self.scalar <= threshold {
self.scalar = 0;
}
self.scalar >= threshold
}
}
fn lerp(start: i64, end: i64, t: f64) -> i64 {
(start as f64 * (1.0 - t) + (end as f64) * t) as i64
}
#[cfg(test)]
mod test {
#[test]
fn lerp_scale() {
for case in [(0.1, 10), (0.5, 31)].iter() {
let t = case.0;
let start = 127.0 * t;
assert_eq!(super::lerp(start as i64, 0, t), case.1);
}
}
#[test]
fn lerper() {
use super::Lerper;
let mut lerper = Lerper::init(15.0, 127, -128, 0);
for case in [(127, 3, 126), (100, 8, 66), (-124, 8, -82)].iter() {
let scalar = case.0;
let now = case.1;
let want = case.2;
lerper.update(scalar);
let result = lerper.apply(now);
assert_eq!(result, want);
}
}
}