Skip to main content

mraphics_core/animation/predefined/
basic.rs

1use crate::{
2    Action, Animation, MeshHandle, MeshLike, MeshPool, MraphicsID, RenderInstance, Scene,
3    anim_curve::{AnimCurve, EaseInOutCubic},
4};
5use nalgebra::{UnitQuaternion, UnitVector3, Vector3};
6use std::{cell::RefCell, marker::PhantomData, rc::Rc};
7
8pub struct MeshAnimation<'res, M, Update, Start, Stop, C>
9where
10    M: MeshLike + 'static,
11    Update: FnMut(&mut M, &mut RenderInstance, f32, f32) + 'res,
12    Start: FnMut() + 'res,
13    Stop: FnMut() + 'res,
14    C: AnimCurve + 'static,
15{
16    pub mesh_id: MraphicsID,
17    pub on_update: Update,
18    pub on_start: Start,
19    pub on_stop: Stop,
20    pub curve: C,
21
22    _marker: PhantomData<&'res M>,
23}
24
25impl<'res, M: MeshLike + 'static>
26    MeshAnimation<'res, M, fn(&mut M, &mut RenderInstance, f32, f32), fn(), fn(), EaseInOutCubic>
27{
28    pub fn new(mesh_handle: &MeshHandle<M>) -> Self {
29        Self {
30            mesh_id: mesh_handle.identifier(),
31            on_update: |_, _, _, _| {},
32            on_start: || {},
33            on_stop: || {},
34            curve: EaseInOutCubic,
35            _marker: PhantomData,
36        }
37    }
38}
39
40impl<'res, M, Update, Start, Stop, C> MeshAnimation<'res, M, Update, Start, Stop, C>
41where
42    M: MeshLike + 'static,
43    Update: FnMut(&mut M, &mut RenderInstance, f32, f32) + 'res,
44    Start: FnMut() + 'res,
45    Stop: FnMut() + 'res,
46    C: AnimCurve + 'static,
47{
48    pub fn with_on_update<F: FnMut(&mut M, &mut RenderInstance, f32, f32) + 'res>(
49        self,
50        closure: F,
51    ) -> MeshAnimation<'res, M, F, Start, Stop, C> {
52        MeshAnimation {
53            mesh_id: self.mesh_id,
54            on_update: closure,
55            on_start: self.on_start,
56            on_stop: self.on_stop,
57            curve: self.curve,
58            _marker: PhantomData,
59        }
60    }
61
62    pub fn with_on_start<F: FnMut() + 'res>(
63        self,
64        closure: F,
65    ) -> MeshAnimation<'res, M, Update, F, Stop, C> {
66        MeshAnimation {
67            mesh_id: self.mesh_id,
68            on_update: self.on_update,
69            on_start: closure,
70            on_stop: self.on_stop,
71            curve: self.curve,
72            _marker: PhantomData,
73        }
74    }
75
76    pub fn with_on_stop<F: FnMut() + 'res>(
77        self,
78        closure: F,
79    ) -> MeshAnimation<'res, M, Update, Start, F, C> {
80        MeshAnimation {
81            mesh_id: self.mesh_id,
82            on_update: self.on_update,
83            on_start: self.on_start,
84            on_stop: closure,
85            curve: self.curve,
86            _marker: PhantomData,
87        }
88    }
89
90    pub fn with_curve<T: AnimCurve + 'static>(
91        self,
92        curve: T,
93    ) -> MeshAnimation<'res, M, Update, Start, Stop, T> {
94        MeshAnimation {
95            mesh_id: self.mesh_id,
96            on_update: self.on_update,
97            on_start: self.on_start,
98            on_stop: self.on_stop,
99            curve,
100            _marker: PhantomData,
101        }
102    }
103}
104
105impl<'res, M, Update, Start, Stop, C> Animation<'res>
106    for MeshAnimation<'res, M, Update, Start, Stop, C>
107where
108    M: MeshLike + 'static,
109    Update: FnMut(&mut M, &mut RenderInstance, f32, f32) + 'res,
110    Start: FnMut() + 'res,
111    Stop: FnMut() + 'res,
112    C: AnimCurve + 'static,
113{
114    fn into_action(
115        mut self,
116        mesh_pool: Rc<RefCell<MeshPool>>,
117        scene: Rc<RefCell<Scene>>,
118    ) -> Action<'res> {
119        let mut out = Action::new();
120
121        out.on_start = Box::new(self.on_start);
122        out.on_stop = Box::new(self.on_stop);
123
124        out.on_update = Box::new(move |progress, elapsed_time| {
125            (self.on_update)(
126                mesh_pool
127                    .borrow_mut()
128                    .acquire_mesh_mut_unchecked(self.mesh_id),
129                scene
130                    .borrow_mut()
131                    .acquire_instance_mut_unchecked(self.mesh_id),
132                self.curve.sample(progress),
133                elapsed_time,
134            )
135        });
136
137        out
138    }
139}
140
141/// Rotates the mesh around a given axis by a given angle.
142pub struct RotateAxisAngle {
143    /// The unique identifier of the mesh to animate.
144    pub mesh_id: MraphicsID,
145
146    /// The axis of rotation, normalized to unit length.
147    pub axis: UnitVector3<f32>,
148
149    /// The rotation angle in radians for this animation.
150    pub angle_rad: f32,
151
152    pub curve: Box<dyn AnimCurve>,
153}
154
155impl RotateAxisAngle {
156    pub fn new<M: MeshLike + 'static>(
157        mesh_handle: &MeshHandle<M>,
158        axis: UnitVector3<f32>,
159        angle_rad: f32,
160    ) -> Self {
161        Self {
162            mesh_id: mesh_handle.identifier(),
163            axis,
164            angle_rad,
165            curve: Box::new(EaseInOutCubic),
166        }
167    }
168
169    pub fn new_normalize<M: MeshLike + 'static>(
170        mesh_handle: &MeshHandle<M>,
171        axis: Vector3<f32>,
172        angle_rad: f32,
173    ) -> Self {
174        Self {
175            mesh_id: mesh_handle.identifier(),
176            axis: UnitVector3::new_normalize(axis),
177            angle_rad,
178            curve: Box::new(EaseInOutCubic),
179        }
180    }
181
182    pub fn with_curve<Curve: AnimCurve + 'static>(mut self, curve: Curve) -> Self {
183        self.curve = Box::new(curve);
184        self
185    }
186}
187
188impl Animation<'static> for RotateAxisAngle {
189    fn into_action(
190        self,
191        _mesh_pool: Rc<RefCell<MeshPool>>,
192        scene: Rc<RefCell<Scene>>,
193    ) -> Action<'static> {
194        let mut out = Action::new();
195        let start_rotation = Rc::new(RefCell::new(UnitQuaternion::identity()));
196
197        let scene_clone = scene.clone();
198        let start_rotation_clone = start_rotation.clone();
199
200        out.on_start = Box::new(move || {
201            start_rotation_clone.borrow_mut().clone_from(
202                scene_clone
203                    .borrow()
204                    .acquire_instance_unchecked(self.mesh_id)
205                    .rotation(),
206            );
207        });
208        out.on_update = Box::new(move |p, _| {
209            scene
210                .borrow_mut()
211                .acquire_instance_mut_unchecked(self.mesh_id)
212                .set_rotation(
213                    &(UnitQuaternion::from_axis_angle(
214                        &self.axis,
215                        self.angle_rad * self.curve.sample(p),
216                    ) * &*start_rotation.borrow()),
217                );
218        });
219
220        out
221    }
222}
223
224/// Shifts the mesh to the specific place
225pub struct MoveTo {
226    pub mesh_id: MraphicsID,
227    pub target_place: Vector3<f32>,
228
229    pub curve: Box<dyn AnimCurve>,
230}
231
232impl MoveTo {
233    pub fn new<M: MeshLike + 'static>(
234        mesh_handle: &MeshHandle<M>,
235        target_place: Vector3<f32>,
236    ) -> Self {
237        Self {
238            mesh_id: mesh_handle.identifier(),
239            target_place,
240            curve: Box::new(EaseInOutCubic),
241        }
242    }
243
244    pub fn with_curve<Curve: AnimCurve + 'static>(mut self, curve: Curve) -> Self {
245        self.curve = Box::new(curve);
246        self
247    }
248}
249
250impl Animation<'static> for MoveTo {
251    fn into_action(
252        self,
253        _mesh_pool: Rc<RefCell<MeshPool>>,
254        scene: Rc<RefCell<Scene>>,
255    ) -> Action<'static> {
256        let mut out = Action::new();
257        let start_place = Rc::new(RefCell::new(Vector3::default()));
258
259        let scene_clone = scene.clone();
260        let start_place_clone = start_place.clone();
261
262        out.on_start = Box::new(move || {
263            start_place_clone.borrow_mut().clone_from(
264                &scene_clone
265                    .borrow()
266                    .acquire_instance_unchecked(self.mesh_id)
267                    .translation()
268                    .vector,
269            );
270        });
271        out.on_update = Box::new(move |p, _| {
272            scene
273                .borrow_mut()
274                .acquire_instance_mut_unchecked(self.mesh_id)
275                .move_to(
276                    &(*start_place.borrow()
277                        + &((self.target_place - *start_place.borrow()) * self.curve.sample(p))),
278                );
279        });
280
281        out
282    }
283}
284
285pub struct ScaleTo {
286    pub mesh_id: MraphicsID,
287    pub target_scale: Vector3<f32>,
288
289    pub curve: Box<dyn AnimCurve>,
290}
291
292impl ScaleTo {
293    pub fn new<M: MeshLike + 'static>(
294        mesh_handle: MeshHandle<M>,
295        target_scale: Vector3<f32>,
296    ) -> Self {
297        Self {
298            mesh_id: mesh_handle.identifier(),
299            target_scale,
300            curve: Box::new(EaseInOutCubic),
301        }
302    }
303
304    pub fn with_curve<Curve: AnimCurve + 'static>(mut self, curve: Curve) -> Self {
305        self.curve = Box::new(curve);
306        self
307    }
308}
309
310impl Animation<'static> for ScaleTo {
311    fn into_action(
312        self,
313        _mesh_pool: Rc<RefCell<MeshPool>>,
314        scene: Rc<RefCell<Scene>>,
315    ) -> Action<'static> {
316        let mut out = Action::new();
317        let start_scale = Rc::new(RefCell::new(Vector3::default()));
318
319        let scene_clone = scene.clone();
320        let start_scale_clone = start_scale.clone();
321
322        out.on_start = Box::new(move || {
323            start_scale_clone.borrow_mut().clone_from(
324                scene_clone
325                    .borrow()
326                    .acquire_instance_unchecked(self.mesh_id)
327                    .scale(),
328            );
329        });
330        out.on_update = Box::new(move |p, _| {
331            scene
332                .borrow_mut()
333                .acquire_instance_mut_unchecked(self.mesh_id)
334                .scale_to(
335                    &(*start_scale.borrow()
336                        + &((self.target_scale - *start_scale.borrow()) * self.curve.sample(p))),
337                );
338        });
339
340        out
341    }
342}
343
344pub struct ScaleBy {
345    pub mesh_id: MraphicsID,
346    pub scale_factor: Vector3<f32>,
347
348    pub curve: Box<dyn AnimCurve>,
349}
350
351impl ScaleBy {
352    pub fn new<M: MeshLike + 'static>(
353        mesh_handle: MeshHandle<M>,
354        scale_factor: Vector3<f32>,
355    ) -> Self {
356        Self {
357            mesh_id: mesh_handle.identifier(),
358            scale_factor,
359
360            curve: Box::new(EaseInOutCubic),
361        }
362    }
363
364    pub fn with_curve<Curve: AnimCurve + 'static>(mut self, curve: Curve) -> Self {
365        self.curve = Box::new(curve);
366        self
367    }
368}
369
370impl Animation<'static> for ScaleBy {
371    fn into_action(
372        self,
373        _mesh_pool: Rc<RefCell<MeshPool>>,
374        scene: Rc<RefCell<Scene>>,
375    ) -> Action<'static> {
376        let mut out = Action::new();
377        let start_scale = Rc::new(RefCell::new(Vector3::default()));
378
379        let scene_clone = scene.clone();
380        let start_scale_clone = start_scale.clone();
381
382        out.on_start = Box::new(move || {
383            start_scale_clone.borrow_mut().clone_from(
384                scene_clone
385                    .borrow()
386                    .acquire_instance_unchecked(self.mesh_id)
387                    .scale(),
388            );
389        });
390        out.on_update = Box::new(move |p, _| {
391            scene
392                .borrow_mut()
393                .acquire_instance_mut_unchecked(self.mesh_id)
394                .scale_to(&start_scale.borrow().component_mul(
395                    &(Vector3::from_element(1.0)
396                        + (self.scale_factor - Vector3::from_element(1.0)) * self.curve.sample(p)),
397                ));
398        });
399
400        out
401    }
402}