ranim_core/
lib.rs

1//! The core of ranim.
2//!
3//!
4#![warn(missing_docs)]
5#![cfg_attr(docsrs, feature(doc_cfg))]
6#![allow(rustdoc::private_intra_doc_links)]
7#![doc(
8    html_logo_url = "https://raw.githubusercontent.com/AzurIce/ranim/refs/heads/main/assets/ranim.svg",
9    html_favicon_url = "https://raw.githubusercontent.com/AzurIce/ranim/refs/heads/main/assets/ranim.svg"
10)]
11pub mod animation;
12/// Color
13pub mod color;
14/// Component data
15pub mod components;
16/// The structure to encode animation spans
17pub mod timeline;
18/// Fondamental traits
19pub mod traits;
20/// Utils
21pub mod utils;
22
23pub mod core_item;
24/// The [`core_item::CoreItem`] store
25pub mod store;
26
27pub mod anchor;
28
29pub use glam;
30pub use num;
31
32/// Prelude
33pub mod prelude {
34    pub use crate::color::prelude::*;
35    pub use crate::traits::*;
36
37    pub use crate::core_item::camera_frame::CameraFrame;
38    pub use crate::timeline::{TimelineFunc, TimelinesFunc};
39    pub use crate::{RanimScene, TimeMark, TimelineId};
40}
41
42use crate::{animation::StaticAnim, core_item::CoreItem, timeline::Timeline};
43
44/// Extract a [`Extract::Target`] from reference.
45pub trait Extract {
46    /// The extraction result
47    type Target: Clone;
48    /// Extract a [`Extract::Target`] from reference.
49    fn extract_into(&self, buf: &mut Vec<Self::Target>);
50    /// Extract a [`Extract::Target`] from reference.
51    fn extract(&self) -> Vec<Self::Target> {
52        let mut buf = Vec::new();
53        self.extract_into(&mut buf);
54        buf
55    }
56}
57
58impl<E: Extract, I> Extract for I
59where
60    for<'a> &'a I: IntoIterator<Item = &'a E>,
61{
62    type Target = E::Target;
63    fn extract_into(&self, buf: &mut Vec<Self::Target>) {
64        for e in self {
65            e.extract_into(buf);
66        }
67    }
68}
69
70use crate::timeline::{AnimationInfo, TimelineFunc, TimelinesFunc};
71use tracing::trace;
72
73use std::fmt::Debug;
74
75/// TimeMark
76#[derive(Debug, Clone)]
77pub enum TimeMark {
78    /// Capture a picture with a name
79    Capture(String),
80}
81
82/// The id of a timeline.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
84pub struct TimelineId(usize);
85
86impl TimelineId {
87    /// Get the inner id.
88    pub fn id(&self) -> usize {
89        self.0
90    }
91}
92
93// MARK: RanimScene
94/// The main struct that offers the ranim's API, and encodes animations
95#[derive(Default)]
96pub struct RanimScene {
97    pub(crate) timelines: Vec<Timeline>,
98    pub(crate) time_marks: Vec<(f64, TimeMark)>,
99}
100
101impl RanimScene {
102    /// Seals the scene to [`SealedRanimScene`].
103    pub fn seal(mut self) -> SealedRanimScene {
104        let total_secs = self.timelines.max_total_secs();
105        self.timelines.forward_to(total_secs);
106        self.timelines.seal();
107        SealedRanimScene {
108            total_secs,
109            timelines: self.timelines,
110            time_marks: self.time_marks,
111        }
112    }
113    /// Create a new [`RanimScene`]
114    pub fn new() -> Self {
115        Self::default()
116    }
117
118    /// Insert an empty timeline.
119    pub fn insert_empty(&mut self) -> TimelineId {
120        self.insert_empty_at(0.0)
121    }
122
123    /// Insert an empty timeline and forward it to the given sec.
124    pub fn insert_empty_at(&mut self, sec: f64) -> TimelineId {
125        self.insert_with(|t| {
126            t.forward_to(sec);
127        })
128    }
129
130    /// Insert a timeline at `0.0` sec and play [`StaticAnim::show`] on it.
131    pub fn insert<T: Extract<Target = CoreItem> + Clone + 'static>(
132        &mut self,
133        item: T,
134    ) -> TimelineId {
135        self.insert_at(item, 0.0)
136    }
137
138    /// Insert a timeline at the given sec and play [`StaticAnim::show`] on it.
139    pub fn insert_at<T: Extract<Target = CoreItem> + Clone + 'static>(
140        &mut self,
141        item: T,
142        sec: f64,
143    ) -> TimelineId {
144        self.insert_with(|t| {
145            t.forward_to(sec);
146            t.play(item.show());
147        })
148    }
149
150    /// Insert a empty timeline and call `f` on it.
151    pub fn insert_with(&mut self, mut f: impl FnMut(&mut Timeline)) -> TimelineId {
152        let id = TimelineId(self.timelines.len());
153        let mut timeline = Timeline::new();
154        f(&mut timeline);
155        self.timelines.push(timeline);
156        id
157    }
158
159    /// Get reference of all timelines
160    pub fn timelines(&self) -> &[Timeline] {
161        trace!("timelines");
162        &self.timelines
163    }
164    /// Get mutable reference of all timelines
165    pub fn timelines_mut(&mut self) -> &mut [Timeline] {
166        trace!("timelines_mut");
167        &mut self.timelines
168    }
169    /// Get the reference of timeline(s) by the [`TimelineIndex`].
170    pub fn timeline<'a, T: TimelineIndex<'a>>(&'a self, index: T) -> T::RefOutput {
171        index.get_index_ref(&self.timelines)
172    }
173    /// Get the mutable reference of timeline(s) by the [`TimelineIndex`].
174    pub fn timeline_mut<'a, T: TimelineIndex<'a>>(&'a mut self, index: T) -> T::MutOutput {
175        index.get_index_mut(&mut self.timelines)
176    }
177    /// Inserts an [`TimeMark`]
178    pub fn insert_time_mark(&mut self, sec: f64, time_mark: TimeMark) {
179        self.time_marks.push((sec, time_mark));
180    }
181}
182
183/// The information of an [`Timeline`].
184pub struct TimelineInfo {
185    /// The inner id value of the [`TimelineId`]
186    pub id: usize,
187    /// The animation infos.
188    pub animation_infos: Vec<AnimationInfo>,
189}
190
191impl Debug for RanimScene {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        f.write_fmt(format_args!("Timeline: {} timelines", self.timelines.len()))?;
194        Ok(())
195    }
196}
197
198// MARK: SealedRanimScene
199/// The sealed [`RanimScene`].
200///
201/// the timelines and time marks cannot be modified after sealed. And
202/// once the [`RanimScene`] is sealed, it can be used for evaluating.
203pub struct SealedRanimScene {
204    pub(crate) total_secs: f64,
205    pub(crate) timelines: Vec<Timeline>,
206    pub(crate) time_marks: Vec<(f64, TimeMark)>,
207}
208
209impl SealedRanimScene {
210    /// Get the total seconds of the [`SealedRanimScene`].
211    pub fn total_secs(&self) -> f64 {
212        self.total_secs
213    }
214    /// Get time marks
215    pub fn time_marks(&self) -> &[(f64, TimeMark)] {
216        &self.time_marks
217    }
218
219    /// Get the iterator of timelines
220    pub fn timelines_iter(&self) -> impl Iterator<Item = &Timeline> {
221        self.timelines.iter()
222    }
223
224    /// Get the count of timelines
225    pub fn timelines_cnt(&self) -> usize {
226        self.timelines.len()
227    }
228
229    /// Get timeline infos.
230    pub fn get_timeline_infos(&self) -> Vec<TimelineInfo> {
231        // const MAX_TIMELINE_CNT: usize = 100;
232        self.timelines
233            .iter()
234            .enumerate()
235            // .take(MAX_TIMELINE_CNT)
236            .map(|(id, timeline)| TimelineInfo {
237                id,
238                animation_infos: timeline.get_animation_infos(),
239            })
240            .collect()
241    }
242
243    /// Eval primitives
244    pub fn eval_at_sec(&self, target_sec: f64) -> impl Iterator<Item = ((usize, usize), CoreItem)> {
245        self.timelines_iter()
246            .enumerate()
247            .filter_map(move |(t_id, t)| {
248                t.eval_primitives_at_sec(target_sec)
249                    .map(move |(a_id, res)| res.into_iter().map(move |x| ((t_id, a_id), x)))
250            })
251            .flatten()
252    }
253
254    /// Eval primitives
255    pub fn eval_at_alpha(&self, alpha: f64) -> impl Iterator<Item = ((usize, usize), CoreItem)> {
256        self.eval_at_sec(self.total_secs() * alpha)
257    }
258}
259
260// MARK: TimelineIndex
261/// A trait for indexing timeline(s)
262///
263/// [`RanimScene::timeline`] and [`RanimScene::timeline_mut`] uses the
264/// reference of [`TimelineIndex`] to index the timeline(s).
265///
266/// See [`TimelineQuery`] for more details.
267///
268/// | Index Type | Output Type |
269/// |------------|-------------|
270/// |   `usize`    | `Option<&Timeline>` and `Option<&mut Timeline>` |
271/// |   `TimelineId`    | `&Timeline` and `&mut Timeline` |
272/// |   `TQ: TimelineQuery<'a>`    | `TQ::RessembleResult` and `TQ::RessembleMutResult` |
273/// |   `[TQ: TimelineQuery<'a>; N]`    | `[TQ::RessembleResult; N]` and `Result<[TQ::RessembleMutResult; N], TimelineIndexMutError>` |
274pub trait TimelineIndex<'a> {
275    /// Output of [`TimelineIndex::get_index_ref`]
276    type RefOutput;
277    /// Output of [`TimelineIndex::get_index_mut`]
278    type MutOutput;
279    /// Get the reference of timeline(s) from [`RanimScene`] by the [`TimelineIndex`].
280    fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput;
281    /// Get the mutable reference of timeline(s) from [`RanimScene`] by the [`TimelineIndex`].
282    fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput;
283}
284
285/// A query of timeline.
286///
287/// It is implemented for [`TimelineId`], `(TI: AsRef<TimelineId>, T)`, `&(TI: AsRef<TimelineId>, T)` and `&mut (TI: AsRef<TimelineId>, T)`.
288///
289/// `&(TI: AsRef<TimelineId>, T)` and `&mut (TI: AsRef<TimelineId>, T)` are actually `(TI, &T)` and `(TI, &mut T)`.
290pub trait TimelineQuery<'a> {
291    /// The result of [`TimelineQuery::ressemble`]
292    type RessembleResult;
293    /// The result of [`TimelineQuery::ressemble_mut`]
294    type RessembleMutResult;
295    /// Get the id of the timeline.
296    fn id(&self) -> TimelineId;
297    /// Ressemble the timeline.
298    fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult;
299    /// Ressemble the mutable timeline.
300    fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult;
301}
302
303impl<'a> TimelineQuery<'a> for TimelineId {
304    type RessembleResult = &'a Timeline;
305    type RessembleMutResult = &'a mut Timeline;
306    fn id(&self) -> TimelineId {
307        *self
308    }
309    fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
310        timeline
311    }
312    fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
313        timeline
314    }
315}
316
317impl<'a, TI: AsRef<TimelineId>, T> TimelineQuery<'a> for (TI, T) {
318    type RessembleResult = (&'a Timeline, T);
319    type RessembleMutResult = (&'a mut Timeline, T);
320    fn id(&self) -> TimelineId {
321        *self.0.as_ref()
322    }
323    fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
324        (timeline, self.1)
325    }
326    fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
327        (timeline, self.1)
328    }
329}
330
331impl<'a: 'b, 'b, TI: AsRef<TimelineId>, T> TimelineQuery<'a> for &'b (TI, T) {
332    type RessembleResult = (&'b Timeline, &'b T);
333    type RessembleMutResult = (&'b mut Timeline, &'b T);
334    fn id(&self) -> TimelineId {
335        *self.0.as_ref()
336    }
337    fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
338        (timeline, &self.1)
339    }
340    fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
341        (timeline, &self.1)
342    }
343}
344
345impl<'a: 'b, 'b, TI: AsRef<TimelineId>, T> TimelineQuery<'a> for &'b mut (TI, T) {
346    type RessembleResult = (&'b Timeline, &'b mut T);
347    type RessembleMutResult = (&'b mut Timeline, &'b mut T);
348    fn id(&self) -> TimelineId {
349        *self.0.as_ref()
350    }
351    fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
352        (timeline, &mut self.1)
353    }
354    fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
355        (timeline, &mut self.1)
356    }
357}
358
359impl<'a> TimelineIndex<'a> for usize {
360    type RefOutput = Option<&'a Timeline>;
361    type MutOutput = Option<&'a mut Timeline>;
362    fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput {
363        timelines.get(self)
364    }
365    fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput {
366        timelines.get_mut(self)
367    }
368}
369
370impl AsRef<TimelineId> for TimelineId {
371    fn as_ref(&self) -> &TimelineId {
372        self
373    }
374}
375
376impl<'a, TQ: TimelineQuery<'a>> TimelineIndex<'a> for TQ {
377    type RefOutput = TQ::RessembleResult;
378    type MutOutput = TQ::RessembleMutResult;
379    fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput {
380        let id = self.id();
381        self.ressemble(id.0.get_index_ref(timelines).unwrap())
382    }
383    fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput {
384        let id = self.id();
385        self.ressemble_mut(id.0.get_index_mut(timelines).unwrap())
386    }
387}
388
389/// An error of timeline indexing.
390#[derive(Debug)]
391pub enum TimelineIndexMutError {
392    /// The index is overlapping.
393    IndexOverlapping,
394}
395
396impl<'a, TI: TimelineQuery<'a>, const N: usize> TimelineIndex<'a> for [TI; N] {
397    type RefOutput = [TI::RessembleResult; N];
398    type MutOutput = Result<[TI::RessembleMutResult; N], TimelineIndexMutError>;
399    fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput {
400        self.map(|x| {
401            let id = x.id();
402            x.ressemble(id.0.get_index_ref(timelines).unwrap())
403        })
404    }
405    /// Learnt from [`std::slice`]'s `get_disjoint_mut`
406    fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput {
407        // Check for overlapping indices
408        for (i, idx) in self.iter().enumerate() {
409            for idx2 in self[i + 1..].iter() {
410                if idx.id() == idx2.id() {
411                    return Err(TimelineIndexMutError::IndexOverlapping);
412                }
413            }
414        }
415
416        // Collect all indices first
417        let indices: [usize; N] = std::array::from_fn(|i| self[i].id().0);
418
419        // NB: This implementation is written as it is because any variation of
420        // `indices.map(|i| self.get_unchecked_mut(i))` would make miri unhappy,
421        // or generate worse code otherwise. This is also why we need to go
422        // through a raw pointer here.
423        let mut arr: std::mem::MaybeUninit<[TI::RessembleMutResult; N]> =
424            std::mem::MaybeUninit::uninit();
425        let arr_ptr = arr.as_mut_ptr();
426        let timelines_ptr: *mut Timeline = timelines.as_mut_ptr();
427        let self_manually_drop = std::mem::ManuallyDrop::new(self);
428
429        // SAFETY: We've verified that all indices are disjoint and in bounds.
430        // We use raw pointers to get multiple mutable references to different
431        // elements of the slice, which is safe because the indices are disjoint.
432        // We use ManuallyDrop to prevent double-drop of self's elements after
433        // reading them with ptr::read.
434        let res = unsafe {
435            for (i, &idx) in indices.iter().enumerate() {
436                let timeline_ref = &mut *timelines_ptr.add(idx);
437                let ti = std::ptr::read(self_manually_drop.as_ptr().add(i));
438                arr_ptr
439                    .cast::<TI::RessembleMutResult>()
440                    .add(i)
441                    .write(ti.ressemble_mut(timeline_ref));
442            }
443            arr.assume_init()
444        };
445
446        Ok(res)
447    }
448}