#![allow(missing_docs)]
#![allow(dead_code)]
use serde::{Deserialize, Serialize};
#[inline]
pub fn lerp(a: f64, b: f64, t: f64) -> f64 {
a + t * (b - a)
}
#[inline]
pub fn lerp3(a: [f64; 3], b: [f64; 3], t: f64) -> [f64; 3] {
[
lerp(a[0], b[0], t),
lerp(a[1], b[1], t),
lerp(a[2], b[2], t),
]
}
#[inline]
pub fn remap(value: f64, in_min: f64, in_max: f64, out_min: f64, out_max: f64) -> f64 {
let t = if in_max == in_min {
0.0
} else {
(value - in_min) / (in_max - in_min)
};
lerp(out_min, out_max, t)
}
#[inline]
pub fn smoothstep(edge0: f64, edge1: f64, x: f64) -> f64 {
let t = ((x - edge0) / (edge1 - edge0)).clamp(0.0, 1.0);
t * t * (3.0 - 2.0 * t)
}
#[inline]
pub fn smootherstep(edge0: f64, edge1: f64, x: f64) -> f64 {
let t = ((x - edge0) / (edge1 - edge0)).clamp(0.0, 1.0);
t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
}
#[inline]
pub fn exp_decay(current: f64, target: f64, rate: f64, dt: f64) -> f64 {
let t = (-rate * dt).exp();
target + (current - target) * t
}
#[inline]
pub fn exp_decay3(current: [f64; 3], target: [f64; 3], rate: f64, dt: f64) -> [f64; 3] {
[
exp_decay(current[0], target[0], rate, dt),
exp_decay(current[1], target[1], rate, dt),
exp_decay(current[2], target[2], rate, dt),
]
}
pub fn smooth_damp(
current: f64,
target: f64,
velocity: &mut f64,
smooth_time: f64,
max_speed: f64,
dt: f64,
) -> f64 {
let smooth_time = smooth_time.max(1e-6);
let omega = 2.0 / smooth_time;
let x = omega * dt;
let exp_approx = 1.0 / (1.0 + x + 0.48 * x * x + 0.235 * x * x * x);
let original_to = target;
let max_change = max_speed * smooth_time;
let delta = (current - target).clamp(-max_change, max_change);
let target_adj = current - delta;
let temp = (*velocity + omega * delta) * dt;
*velocity = (*velocity - omega * temp) * exp_approx;
let output = target_adj + (delta + temp) * exp_approx;
if (original_to - current > 0.0) == (output > original_to) {
*velocity = (output - original_to) / dt;
return original_to;
}
output
}
pub fn smooth_damp3(
current: [f64; 3],
target: [f64; 3],
velocity: &mut [f64; 3],
smooth_time: f64,
max_speed: f64,
dt: f64,
) -> [f64; 3] {
[
smooth_damp(
current[0],
target[0],
&mut velocity[0],
smooth_time,
max_speed,
dt,
),
smooth_damp(
current[1],
target[1],
&mut velocity[1],
smooth_time,
max_speed,
dt,
),
smooth_damp(
current[2],
target[2],
&mut velocity[2],
smooth_time,
max_speed,
dt,
),
]
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpringFollower {
pub stiffness: f64,
pub damping: f64,
pub value: f64,
velocity: f64,
}
impl SpringFollower {
pub fn new(stiffness: f64) -> Self {
let stiffness = stiffness.max(0.0);
Self {
stiffness,
damping: 2.0 * stiffness.sqrt(),
value: 0.0,
velocity: 0.0,
}
}
pub fn with_damping(stiffness: f64, damping: f64) -> Self {
Self {
stiffness: stiffness.max(0.0),
damping: damping.max(0.0),
value: 0.0,
velocity: 0.0,
}
}
pub fn set_value(&mut self, value: f64) {
self.value = value;
}
pub fn reset(&mut self, value: f64) {
self.value = value;
self.velocity = 0.0;
}
pub fn update(&mut self, target: f64, dt: f64) -> f64 {
let error = self.value - target;
let accel = -self.stiffness * error - self.damping * self.velocity;
self.velocity += accel * dt;
self.value += self.velocity * dt;
self.value
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpringFollower3 {
pub stiffness: f64,
pub damping: f64,
pub value: [f64; 3],
velocity: [f64; 3],
}
impl SpringFollower3 {
pub fn new(stiffness: f64) -> Self {
let stiffness = stiffness.max(0.0);
Self {
stiffness,
damping: 2.0 * stiffness.sqrt(),
value: [0.0; 3],
velocity: [0.0; 3],
}
}
pub fn with_damping(stiffness: f64, damping: f64) -> Self {
Self {
stiffness: stiffness.max(0.0),
damping: damping.max(0.0),
value: [0.0; 3],
velocity: [0.0; 3],
}
}
pub fn set_value(&mut self, value: [f64; 3]) {
self.value = value;
}
pub fn reset(&mut self, value: [f64; 3]) {
self.value = value;
self.velocity = [0.0; 3];
}
pub fn update(&mut self, target: [f64; 3], dt: f64) -> [f64; 3] {
for ((val, vel), tgt) in self
.value
.iter_mut()
.zip(self.velocity.iter_mut())
.zip(target.iter())
{
let error = *val - tgt;
let accel = -self.stiffness * error - self.damping * *vel;
*vel += accel * dt;
*val += *vel * dt;
}
self.value
}
}