Skip to main content

mraphics_core/animation/predefined/
transform.rs

1use crate::{
2    Action, Animation, InstanceUpdater, Interpolatable, MeshHandle, MeshLike, MeshPool, MraphicsID,
3    Representable, Scene,
4    anim_curve::{AnimCurve, Linear},
5};
6use nalgebra::{Matrix3, Vector3};
7use std::{cell::RefCell, marker::PhantomData, rc::Rc};
8
9/// Requriements to perform a [`PointwiseTransform`] or [`MatrixTransform`]
10pub trait Transformable: MeshLike + Representable
11where
12    Self::Intermediate: Interpolatable + InstanceUpdater,
13{
14    /// Applies a transform function to self, and returns a intermediate representation.
15    ///
16    /// The intermediate representation must satisfies
17    /// - [`InstanceUpdater`]: For updating geometry view.
18    /// - [`Interpolatable`]: For performing a tweening animation.
19    fn apply_transform<Trans: Fn(&[f32; 3]) -> [f32; 3]>(
20        &self,
21        transform: Trans,
22    ) -> Self::Intermediate;
23}
24
25pub struct PointwiseTransform<Trans, M>
26where
27    Trans: Fn(&[f32; 3]) -> [f32; 3] + 'static,
28    M: Transformable + 'static,
29    M::Intermediate: Interpolatable + InstanceUpdater,
30{
31    /// The unique identifier of the mesh to animate.
32    pub mesh_id: MraphicsID,
33
34    /// The transform function to apply.
35    pub transform: Trans,
36
37    /// Animation curve.
38    pub curve: Box<dyn AnimCurve>,
39
40    _marker: PhantomData<M>,
41}
42
43impl<Trans, M> PointwiseTransform<Trans, M>
44where
45    Trans: Fn(&[f32; 3]) -> [f32; 3] + 'static,
46    M: Transformable + 'static,
47    M::Intermediate: Interpolatable + InstanceUpdater,
48{
49    pub fn new(mesh_handle: &MeshHandle<M>, trans: Trans) -> Self {
50        Self {
51            mesh_id: mesh_handle.identifier(),
52            transform: trans,
53
54            curve: Box::new(Linear),
55
56            _marker: PhantomData,
57        }
58    }
59
60    pub fn with_curve<Curve: AnimCurve + 'static>(mut self, curve: Curve) -> Self {
61        self.curve = Box::new(curve);
62        self
63    }
64}
65
66impl<Trans, M> Animation<'static> for PointwiseTransform<Trans, M>
67where
68    Trans: Fn(&[f32; 3]) -> [f32; 3] + 'static,
69    M: Transformable + 'static,
70    M::Intermediate: Interpolatable + InstanceUpdater,
71{
72    fn into_action(
73        self,
74        mesh_pool: Rc<RefCell<MeshPool>>,
75        scene: Rc<RefCell<Scene>>,
76    ) -> Action<'static> {
77        let mut out = Action::new();
78        let original = Rc::new(RefCell::new(None));
79        let transformed = Rc::new(RefCell::new(None));
80
81        out.on_start = Box::new({
82            let oringinal = original.clone();
83            let transformed = transformed.clone();
84            let mesh_pool = mesh_pool.clone();
85            move || {
86                *oringinal.borrow_mut() = Some(
87                    mesh_pool
88                        .borrow()
89                        .acquire_mesh_unchecked::<M>(self.mesh_id)
90                        .as_intermediate(),
91                );
92
93                *transformed.borrow_mut() = Some(
94                    mesh_pool
95                        .borrow()
96                        .acquire_mesh_unchecked::<M>(self.mesh_id)
97                        .apply_transform(&self.transform),
98                );
99            }
100        });
101
102        out.on_update = Box::new({
103            let original = original.clone();
104            let transformed = transformed.clone();
105            move |p: f32, _t: f32| {
106                original
107                    .borrow()
108                    .as_ref()
109                    .unwrap()
110                    .interpolate(
111                        &transformed.borrow().as_ref().unwrap(),
112                        self.curve.sample(p),
113                    )
114                    .update_instance(
115                        &mut scene
116                            .borrow_mut()
117                            .acquire_instance_mut_unchecked(self.mesh_id),
118                    );
119            }
120        });
121
122        out.on_stop = Box::new({
123            let transformed = transformed.clone();
124            move || {
125                mesh_pool
126                    .borrow_mut()
127                    .acquire_mesh_mut_unchecked::<M>(self.mesh_id)
128                    .update_from_intermediate(transformed.borrow().as_ref().unwrap());
129            }
130        });
131
132        out
133    }
134}
135
136pub struct MatrixTransform<M>
137where
138    M: Transformable + 'static,
139    M::Intermediate: Interpolatable + InstanceUpdater,
140{
141    /// The unique identifier of the mesh to animate.
142    pub mesh_id: MraphicsID,
143
144    pub matrix: Matrix3<f32>,
145
146    pub curve: Box<dyn AnimCurve>,
147
148    _marker: PhantomData<M>,
149}
150
151impl<M> MatrixTransform<M>
152where
153    M: Transformable + 'static,
154    M::Intermediate: Interpolatable + InstanceUpdater,
155{
156    pub fn new(mesh_handle: &MeshHandle<M>, matrix: Matrix3<f32>) -> Self {
157        Self {
158            mesh_id: mesh_handle.identifier(),
159            matrix,
160
161            curve: Box::new(Linear),
162
163            _marker: PhantomData,
164        }
165    }
166
167    pub fn with_curve<Curve: AnimCurve + 'static>(mut self, curve: Curve) -> Self {
168        self.curve = Box::new(curve);
169        self
170    }
171}
172
173impl<M> Animation<'static> for MatrixTransform<M>
174where
175    M: Transformable + 'static,
176    M::Intermediate: Interpolatable + InstanceUpdater,
177{
178    fn into_action(
179        self,
180        mesh_pool: Rc<RefCell<MeshPool>>,
181        scene: Rc<RefCell<Scene>>,
182    ) -> Action<'static> {
183        let mut out = Action::new();
184        let original = Rc::new(RefCell::new(None));
185        let transformed = Rc::new(RefCell::new(None));
186
187        out.on_start = Box::new({
188            let oringinal = original.clone();
189            let transformed = transformed.clone();
190            let mesh_pool = mesh_pool.clone();
191            move || {
192                *oringinal.borrow_mut() = Some(
193                    mesh_pool
194                        .borrow()
195                        .acquire_mesh_unchecked::<M>(self.mesh_id)
196                        .as_intermediate(),
197                );
198
199                *transformed.borrow_mut() = Some(
200                    mesh_pool
201                        .borrow()
202                        .acquire_mesh_unchecked::<M>(self.mesh_id)
203                        .apply_transform(|point: &[f32; 3]| {
204                            let transformed = self.matrix * &Vector3::from_row_slice(point);
205                            return [transformed[0], transformed[1], transformed[2]];
206                        }),
207                );
208            }
209        });
210
211        out.on_update = Box::new({
212            let original = original.clone();
213            let transformed = transformed.clone();
214            move |p: f32, _t: f32| {
215                original
216                    .borrow()
217                    .as_ref()
218                    .unwrap()
219                    .interpolate(
220                        &transformed.borrow().as_ref().unwrap(),
221                        self.curve.sample(p),
222                    )
223                    .update_instance(
224                        &mut scene
225                            .borrow_mut()
226                            .acquire_instance_mut_unchecked(self.mesh_id),
227                    );
228            }
229        });
230
231        out.on_stop = Box::new({
232            let transformed = transformed.clone();
233            move || {
234                mesh_pool
235                    .borrow_mut()
236                    .acquire_mesh_mut_unchecked::<M>(self.mesh_id)
237                    .update_from_intermediate(transformed.borrow().as_ref().unwrap());
238            }
239        });
240
241        out
242    }
243}