pfx_physics/rigid/
drive.rs1use pfx_core::motion::Spring;
2
3use super::Pose;
4use super::convert::{Iso, iso, lerp_iso};
5
6#[derive(Clone, Copy, Debug)]
7pub struct Ease {
8 pub from: Pose,
9 pub to: Pose,
10 pub duration: f32,
11 pub elapsed: f32,
12 pub curve: fn(f32) -> f32,
13}
14
15impl Ease {
16 pub fn new(from: Pose, to: Pose, duration: f32, curve: fn(f32) -> f32) -> Self {
17 Self {
18 from,
19 to,
20 duration,
21 elapsed: 0.0,
22 curve,
23 }
24 }
25
26 pub fn done(&self) -> bool {
27 self.elapsed >= self.duration
28 }
29
30 fn at(&self) -> Iso {
31 let t = if self.duration > 0.0 {
32 (self.elapsed / self.duration).clamp(0.0, 1.0)
33 } else {
34 1.0
35 };
36 lerp_iso(&iso(self.from), &iso(self.to), (self.curve)(t))
37 }
38}
39
40#[derive(Clone, Copy, Debug)]
41pub enum Drive {
42 Spring(Spring<[f32; 3]>),
43 Ease(Ease),
44}
45
46impl Drive {
47 pub fn spring(stiffness: f32, position: [f32; 3]) -> Self {
48 Self::Spring(Spring::at(stiffness, position))
49 }
50
51 pub fn ease(from: Pose, to: Pose, duration: f32, curve: fn(f32) -> f32) -> Self {
52 Self::Ease(Ease::new(from, to, duration, curve))
53 }
54
55 pub fn settled(&self) -> bool {
56 match self {
57 Self::Spring(spring) => spring.settled(),
58 Self::Ease(ease) => ease.done(),
59 }
60 }
61
62 pub(crate) fn advance(&mut self, dt: f32, current: &Iso) -> Iso {
63 match self {
64 Self::Spring(spring) => {
65 spring.step(dt);
66 let [x, y, z] = spring.value;
67 Iso::from_parts(super::convert::Vec3::new(x, y, z), current.rotation)
68 }
69 Self::Ease(ease) => {
70 ease.elapsed = (ease.elapsed + dt).min(ease.duration.max(0.0));
71 ease.at()
72 }
73 }
74 }
75}