#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![allow(rustdoc::private_intra_doc_links)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/AzurIce/ranim/refs/heads/main/assets/ranim.svg",
html_favicon_url = "https://raw.githubusercontent.com/AzurIce/ranim/refs/heads/main/assets/ranim.svg"
)]
pub mod animation;
pub mod color;
pub mod components;
pub mod timeline;
pub mod traits;
pub mod utils;
pub mod core_item;
pub mod store;
pub mod anchor;
pub use glam;
pub use num;
pub mod prelude {
pub use crate::color::prelude::*;
pub use crate::traits::*;
pub use crate::core_item::camera_frame::CameraFrame;
pub use crate::timeline::{TimelineFunc, TimelinesFunc};
pub use crate::{RanimScene, TimeMark, TimelineId};
}
use crate::{animation::StaticAnim, core_item::CoreItem, timeline::Timeline};
pub trait Extract {
type Target: Clone;
fn extract_into(&self, buf: &mut Vec<Self::Target>);
fn extract(&self) -> Vec<Self::Target> {
let mut buf = Vec::new();
self.extract_into(&mut buf);
buf
}
}
impl<E: Extract, I> Extract for I
where
for<'a> &'a I: IntoIterator<Item = &'a E>,
{
type Target = E::Target;
fn extract_into(&self, buf: &mut Vec<Self::Target>) {
for e in self {
e.extract_into(buf);
}
}
}
use crate::timeline::{AnimationInfo, TimelineFunc, TimelinesFunc};
use tracing::trace;
use std::fmt::Debug;
#[derive(Debug, Clone)]
pub enum TimeMark {
Capture(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TimelineId(usize);
impl TimelineId {
pub fn id(&self) -> usize {
self.0
}
}
#[derive(Default)]
pub struct RanimScene {
pub(crate) timelines: Vec<Timeline>,
pub(crate) time_marks: Vec<(f64, TimeMark)>,
}
impl RanimScene {
pub fn seal(mut self) -> SealedRanimScene {
let total_secs = self.timelines.max_total_secs();
self.timelines.forward_to(total_secs);
self.timelines.seal();
SealedRanimScene {
total_secs,
timelines: self.timelines,
time_marks: self.time_marks,
}
}
pub fn new() -> Self {
Self::default()
}
pub fn insert_empty(&mut self) -> TimelineId {
self.insert_empty_at(0.0)
}
pub fn insert_empty_at(&mut self, sec: f64) -> TimelineId {
self.insert_with(|t| {
t.forward_to(sec);
})
}
pub fn insert<T: Extract<Target = CoreItem> + Clone + 'static>(
&mut self,
item: T,
) -> TimelineId {
self.insert_at(item, 0.0)
}
pub fn insert_at<T: Extract<Target = CoreItem> + Clone + 'static>(
&mut self,
item: T,
sec: f64,
) -> TimelineId {
self.insert_with(|t| {
t.forward_to(sec);
t.play(item.show());
})
}
pub fn insert_with(&mut self, mut f: impl FnMut(&mut Timeline)) -> TimelineId {
let id = TimelineId(self.timelines.len());
let mut timeline = Timeline::new();
f(&mut timeline);
self.timelines.push(timeline);
id
}
pub fn timelines(&self) -> &[Timeline] {
trace!("timelines");
&self.timelines
}
pub fn timelines_mut(&mut self) -> &mut [Timeline] {
trace!("timelines_mut");
&mut self.timelines
}
pub fn timeline<'a, T: TimelineIndex<'a>>(&'a self, index: T) -> T::RefOutput {
index.get_index_ref(&self.timelines)
}
pub fn timeline_mut<'a, T: TimelineIndex<'a>>(&'a mut self, index: T) -> T::MutOutput {
index.get_index_mut(&mut self.timelines)
}
pub fn insert_time_mark(&mut self, sec: f64, time_mark: TimeMark) {
self.time_marks.push((sec, time_mark));
}
}
pub struct TimelineInfo {
pub id: usize,
pub animation_infos: Vec<AnimationInfo>,
}
impl Debug for RanimScene {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("Timeline: {} timelines", self.timelines.len()))?;
Ok(())
}
}
pub struct SealedRanimScene {
pub(crate) total_secs: f64,
pub(crate) timelines: Vec<Timeline>,
pub(crate) time_marks: Vec<(f64, TimeMark)>,
}
impl SealedRanimScene {
pub fn total_secs(&self) -> f64 {
self.total_secs
}
pub fn time_marks(&self) -> &[(f64, TimeMark)] {
&self.time_marks
}
pub fn timelines_iter(&self) -> impl Iterator<Item = &Timeline> {
self.timelines.iter()
}
pub fn timelines_cnt(&self) -> usize {
self.timelines.len()
}
pub fn get_timeline_infos(&self) -> Vec<TimelineInfo> {
self.timelines
.iter()
.enumerate()
.map(|(id, timeline)| TimelineInfo {
id,
animation_infos: timeline.get_animation_infos(),
})
.collect()
}
pub fn eval_at_sec(&self, target_sec: f64) -> impl Iterator<Item = ((usize, usize), CoreItem)> {
self.timelines_iter()
.enumerate()
.filter_map(move |(t_id, t)| {
t.eval_primitives_at_sec(target_sec)
.map(move |(a_id, res)| res.into_iter().map(move |x| ((t_id, a_id), x)))
})
.flatten()
}
pub fn eval_at_alpha(&self, alpha: f64) -> impl Iterator<Item = ((usize, usize), CoreItem)> {
self.eval_at_sec(self.total_secs() * alpha)
}
}
pub trait TimelineIndex<'a> {
type RefOutput;
type MutOutput;
fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput;
fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput;
}
pub trait TimelineQuery<'a> {
type RessembleResult;
type RessembleMutResult;
fn id(&self) -> TimelineId;
fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult;
fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult;
}
impl<'a> TimelineQuery<'a> for TimelineId {
type RessembleResult = &'a Timeline;
type RessembleMutResult = &'a mut Timeline;
fn id(&self) -> TimelineId {
*self
}
fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
timeline
}
fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
timeline
}
}
impl<'a, TI: AsRef<TimelineId>, T> TimelineQuery<'a> for (TI, T) {
type RessembleResult = (&'a Timeline, T);
type RessembleMutResult = (&'a mut Timeline, T);
fn id(&self) -> TimelineId {
*self.0.as_ref()
}
fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
(timeline, self.1)
}
fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
(timeline, self.1)
}
}
impl<'a: 'b, 'b, TI: AsRef<TimelineId>, T> TimelineQuery<'a> for &'b (TI, T) {
type RessembleResult = (&'b Timeline, &'b T);
type RessembleMutResult = (&'b mut Timeline, &'b T);
fn id(&self) -> TimelineId {
*self.0.as_ref()
}
fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
(timeline, &self.1)
}
fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
(timeline, &self.1)
}
}
impl<'a: 'b, 'b, TI: AsRef<TimelineId>, T> TimelineQuery<'a> for &'b mut (TI, T) {
type RessembleResult = (&'b Timeline, &'b mut T);
type RessembleMutResult = (&'b mut Timeline, &'b mut T);
fn id(&self) -> TimelineId {
*self.0.as_ref()
}
fn ressemble(self, timeline: &'a Timeline) -> Self::RessembleResult {
(timeline, &mut self.1)
}
fn ressemble_mut(self, timeline: &'a mut Timeline) -> Self::RessembleMutResult {
(timeline, &mut self.1)
}
}
impl<'a> TimelineIndex<'a> for usize {
type RefOutput = Option<&'a Timeline>;
type MutOutput = Option<&'a mut Timeline>;
fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput {
timelines.get(self)
}
fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput {
timelines.get_mut(self)
}
}
impl AsRef<TimelineId> for TimelineId {
fn as_ref(&self) -> &TimelineId {
self
}
}
impl<'a, TQ: TimelineQuery<'a>> TimelineIndex<'a> for TQ {
type RefOutput = TQ::RessembleResult;
type MutOutput = TQ::RessembleMutResult;
fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput {
let id = self.id();
self.ressemble(id.0.get_index_ref(timelines).unwrap())
}
fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput {
let id = self.id();
self.ressemble_mut(id.0.get_index_mut(timelines).unwrap())
}
}
#[derive(Debug)]
pub enum TimelineIndexMutError {
IndexOverlapping,
}
impl<'a, TI: TimelineQuery<'a>, const N: usize> TimelineIndex<'a> for [TI; N] {
type RefOutput = [TI::RessembleResult; N];
type MutOutput = Result<[TI::RessembleMutResult; N], TimelineIndexMutError>;
fn get_index_ref(self, timelines: &'a [Timeline]) -> Self::RefOutput {
self.map(|x| {
let id = x.id();
x.ressemble(id.0.get_index_ref(timelines).unwrap())
})
}
fn get_index_mut(self, timelines: &'a mut [Timeline]) -> Self::MutOutput {
for (i, idx) in self.iter().enumerate() {
for idx2 in self[i + 1..].iter() {
if idx.id() == idx2.id() {
return Err(TimelineIndexMutError::IndexOverlapping);
}
}
}
let indices: [usize; N] = std::array::from_fn(|i| self[i].id().0);
let mut arr: std::mem::MaybeUninit<[TI::RessembleMutResult; N]> =
std::mem::MaybeUninit::uninit();
let arr_ptr = arr.as_mut_ptr();
let timelines_ptr: *mut Timeline = timelines.as_mut_ptr();
let self_manually_drop = std::mem::ManuallyDrop::new(self);
let res = unsafe {
for (i, &idx) in indices.iter().enumerate() {
let timeline_ref = &mut *timelines_ptr.add(idx);
let ti = std::ptr::read(self_manually_drop.as_ptr().add(i));
arr_ptr
.cast::<TI::RessembleMutResult>()
.add(i)
.write(ti.ressemble_mut(timeline_ref));
}
arr.assume_init()
};
Ok(res)
}
}