1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#[derive(Clone, Copy, Debug)]
pub struct SpringRuntime {
pub(crate) m_zeta: f32,
pub(crate) w0: f32,
pub(crate) wd: f32,
pub(crate) a: f32,
pub(crate) b: f32,
}
impl SpringRuntime {
pub fn new(mass: f32, stiffness: f32, damping: f32) -> SpringRuntime {
let m_zeta = damping / (2.0 * libm::sqrtf(stiffness * mass));
let m_w0 = libm::sqrtf(stiffness / mass);
if m_zeta < 1.0 {
let m_wd = m_w0 * libm::sqrtf(1.0 - m_zeta * m_zeta);
// Under-damped
SpringRuntime {
m_zeta,
w0: m_w0,
wd: m_wd,
a: 1.0,
b: (m_zeta * m_w0) / m_wd,
}
} else {
// Critically damped (ignoring over-damped case for now).
SpringRuntime {
m_zeta,
w0: m_w0,
wd: 0.0,
a: 1.0,
b: m_w0,
}
}
}
pub fn solve(&self, t: &f32) -> f32 {
let progress = if self.m_zeta < 1.0 {
// Under-damped
libm::expf(-t * self.m_zeta * self.w0)
* (self.a * libm::cosf(self.wd * t) + self.b * libm::sinf(self.wd * t))
} else {
// Critically damped
(self.a + self.b * t) * libm::expf(-t * self.w0)
};
// Map range from [1..0] to [0..1].
1.0 - progress
}
/// The dumbest way to calculate spring duration taken from animejs https://github.com/juliangarnier/anime/blob/master/src/index.js#L100
/// Not the best, but it looks there is no formula for precise calculation of spring dumping timing.
/// Must be called in compile time
pub fn get_duration(&self) -> f32 {
let frame_duration = 0.166667; // for 60 fps
let mut elapsed = 0.0;
let mut not_animating_frames_count = 0u8;
loop {
elapsed += frame_duration;
if self.solve(&elapsed) == 1.0 {
not_animating_frames_count += 1;
if not_animating_frames_count >= 128 {
break;
}
} else {
not_animating_frames_count = 0
}
}
elapsed * frame_duration
}
}