1#![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;
13pub mod color;
15pub mod components;
17pub mod timeline;
19pub mod traits;
21pub mod utils;
23
24pub mod primitives;
26pub mod store;
28
29pub use glam;
30
31pub mod prelude {
33 pub use crate::color::prelude::*;
34 pub use crate::traits::*;
35
36 pub use crate::primitives::camera_frame::CameraFrame;
37 pub use crate::timeline::{TimelineFunc, TimelinesFunc};
38 pub use crate::{ItemId, RanimScene, TimeMark};
39}
40
41use crate::primitives::{CoreItem, Primitive, Primitives};
42#[cfg(target_arch = "wasm32")]
43use wasm_bindgen::prelude::*;
44
45pub trait Extract {
47 type Target: Primitive + Clone;
49 fn extract(&self) -> Vec<Self::Target>;
51 fn extract_to_primitives(&self) -> Primitives {
53 Self::Target::build_primitives(self.extract())
54 }
55}
56
57use crate::timeline::{AnimationInfo, ItemDynTimelines, ItemTimeline, TimelineFunc, TimelinesFunc};
58use itertools::Itertools;
59use tracing::trace;
60
61use std::{any::TypeId, fmt::Debug, ops::Deref};
62
63#[doc(hidden)]
65#[derive(Clone)]
66#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
67pub struct Scene {
68 #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
69 pub name: &'static str,
70 #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
71 pub constructor: fn(&mut RanimScene),
72 #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
73 pub config: SceneConfig,
74 #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
75 pub outputs: &'static [Output],
76}
77
78pub use inventory;
79
80inventory::collect!(Scene);
81
82#[doc(hidden)]
83#[unsafe(no_mangle)]
84pub extern "C" fn get_scene(idx: usize) -> *const Scene {
85 inventory::iter::<Scene>().skip(idx).take(1).next().unwrap()
86}
87
88#[doc(hidden)]
89#[unsafe(no_mangle)]
90pub extern "C" fn scene_cnt() -> usize {
91 inventory::iter::<Scene>().count()
92}
93
94#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
96pub fn find_scene(name: &str) -> Option<Scene> {
97 inventory::iter::<Scene>().find(|s| s.name == name).cloned()
98}
99
100#[derive(Debug, Clone)]
102pub struct SceneConfig {
103 pub frame_height: f64,
107 pub clear_color: &'static str,
109}
110
111impl Default for SceneConfig {
112 fn default() -> Self {
113 Self {
114 frame_height: 8.0,
115 clear_color: "#333333ff",
116 }
117 }
118}
119
120#[derive(Debug, Clone)]
122#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
123pub struct Output {
124 pub width: u32,
126 pub height: u32,
128 pub fps: u32,
130 pub save_frames: bool,
132 #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
136 pub dir: &'static str,
137}
138
139impl Default for Output {
140 fn default() -> Self {
141 Self::DEFAULT
142 }
143}
144
145impl Output {
146 pub const DEFAULT: Self = Self {
148 width: 1920,
149 height: 1080,
150 fps: 60,
151 save_frames: false,
152 dir: "./",
153 };
154}
155
156#[derive(Debug, Clone)]
158pub enum TimeMark {
159 Capture(String),
161}
162
163pub struct ItemId<T> {
166 id: usize,
167 _phantom: std::marker::PhantomData<T>,
168}
169
170impl<T> Debug for ItemId<T> {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 f.debug_struct("ItemId")
173 .field("id", &self.id)
174 .field("type", &std::any::type_name::<T>())
175 .finish()
176 }
177}
178
179impl<T> Deref for ItemId<T> {
180 type Target = usize;
181 fn deref(&self) -> &Self::Target {
182 &self.id
183 }
184}
185
186impl<T> ItemId<T> {
187 pub fn inner(&self) -> usize {
189 self.id
190 }
191 pub(crate) fn new(id: usize) -> Self {
192 Self {
193 id,
194 _phantom: std::marker::PhantomData,
195 }
196 }
197}
198
199pub trait SceneConstructor: Send + Sync {
206 fn construct(&self, r: &mut RanimScene);
208
209 fn build_scene(&self) -> SealedRanimScene {
211 let mut scene = RanimScene::new();
212 self.construct(&mut scene);
213 scene.seal()
214 }
215}
216impl<F: Fn(&mut RanimScene) + Send + Sync> SceneConstructor for F {
219 fn construct(&self, r: &mut RanimScene) {
220 self(r);
221 }
222}
223
224#[derive(Default)]
228pub struct RanimScene {
229 pub(crate) timelines: Vec<ItemDynTimelines>,
231 pub(crate) time_marks: Vec<(f64, TimeMark)>,
232}
233
234impl RanimScene {
235 pub fn seal(mut self) -> SealedRanimScene {
237 let total_secs = self.timelines.max_total_secs();
238 self.timelines.forward_to(total_secs);
239 self.timelines.seal();
240 SealedRanimScene {
241 total_secs,
242 timelines: self.timelines,
243 time_marks: self.time_marks,
244 }
245 }
246 pub fn new() -> Self {
248 Self::default()
249 }
250
251 pub fn insert<T: Extract + Clone + 'static>(&mut self, state: T) -> ItemId<T> {
257 self.insert_and(state, |_| {})
258 }
259 pub fn insert_and_show<T: Extract + Clone + 'static>(&mut self, state: T) -> ItemId<T> {
261 self.insert_and(state, |timeline| {
262 timeline.show();
263 })
264 }
265 pub fn insert_and<T: Extract + Clone + 'static>(
267 &mut self,
268 state: T,
269 f: impl FnOnce(&mut ItemTimeline<T>),
270 ) -> ItemId<T> {
271 let id = ItemId::new(self.timelines.len());
272 trace!("insert_and type of {:?}, id: {id:?}", TypeId::of::<T>());
273 let mut item_timeline = ItemTimeline::<T>::new(state);
274 f(&mut item_timeline);
275
276 let mut timeline = ItemDynTimelines::new();
277 timeline.push(item_timeline);
278 self.timelines.push(timeline);
279 id
280 }
281 pub fn map<T: Extract + Clone + 'static, E: Extract + Clone + 'static>(
285 &mut self,
286 item_id: ItemId<T>,
287 map_fn: impl FnOnce(T) -> E,
288 ) -> ItemId<E> {
289 trace!(
290 "map {item_id:?} {:?} -> {:?}",
291 TypeId::of::<T>(),
292 TypeId::of::<E>()
293 );
294 let dyn_item_timeline = self.timelines.get_mut(*item_id).unwrap();
300 dyn_item_timeline.apply_map(map_fn);
301 ItemId::new(item_id.inner())
302 }
303
304 pub fn timelines(&self) -> &[ItemDynTimelines] {
306 trace!("timelines");
307 &self.timelines
308 }
309 pub fn timelines_mut(&mut self) -> &mut [ItemDynTimelines] {
311 trace!("timelines_mut");
312 &mut self.timelines
313 }
314 pub fn timeline<'a, T: TimelineIndex<'a>>(&'a self, index: &T) -> T::RefOutput {
316 index.timeline(self)
317 }
318 pub fn timeline_mut<'a, T: TimelineIndex<'a>>(&'a mut self, index: &T) -> T::MutOutput {
320 index.timeline_mut(self)
321 }
322 pub fn insert_time_mark(&mut self, sec: f64, time_mark: TimeMark) {
324 self.time_marks.push((sec, time_mark));
325 }
326}
327
328pub struct ItemDynTimelinesInfo {
330 pub id: usize,
332 pub animation_infos: Vec<AnimationInfo>,
334}
335
336impl Debug for RanimScene {
337 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
338 f.write_fmt(format_args!("Timeline: {} timelines", self.timelines.len()))?;
339 Ok(())
340 }
341}
342
343pub struct SealedRanimScene {
349 pub(crate) total_secs: f64,
350 pub(crate) timelines: Vec<ItemDynTimelines>,
351 pub(crate) time_marks: Vec<(f64, TimeMark)>,
352}
353
354impl SealedRanimScene {
355 pub fn total_secs(&self) -> f64 {
357 self.total_secs
358 }
359 pub fn time_marks(&self) -> &[(f64, TimeMark)] {
361 &self.time_marks
362 }
363
364 pub fn timelines_iter(&self) -> impl Iterator<Item = &ItemDynTimelines> {
366 self.timelines.iter()
367 }
368
369 pub fn timelines_cnt(&self) -> usize {
371 self.timelines.len()
372 }
373
374 pub fn get_timeline_infos(&self) -> Vec<ItemDynTimelinesInfo> {
376 self.timelines
378 .iter()
379 .enumerate()
380 .map(|(id, timeline)| ItemDynTimelinesInfo {
382 id,
383 animation_infos: timeline.get_animation_infos(),
384 })
385 .collect()
386 }
387
388 pub fn eval_at_sec(&self, target_sec: f64) -> impl Iterator<Item = CoreItem> {
390 self.timelines_iter()
391 .filter_map(move |t| {
392 t.eval_primitives_at_sec(target_sec)
393 .map(|(res, _id_hash)| res.to_owned().boom())
394 })
395 .flatten()
396 }
397
398 pub fn eval_at_alpha(&self, alpha: f64) -> impl Iterator<Item = CoreItem> {
400 self.eval_at_sec(self.total_secs() * alpha)
401 }
402}
403
404pub trait TimelineIndex<'a> {
416 type RefOutput;
418 type MutOutput;
420 fn timeline(&self, timeline: &'a RanimScene) -> Self::RefOutput;
422 fn timeline_mut(&self, timeline: &'a mut RanimScene) -> Self::MutOutput;
424}
425
426impl<'a> TimelineIndex<'a> for usize {
427 type RefOutput = Option<&'a ItemDynTimelines>;
428 type MutOutput = Option<&'a mut ItemDynTimelines>;
429 fn timeline(&self, r: &'a RanimScene) -> Self::RefOutput {
430 r.timelines.get(*self)
431 }
436 fn timeline_mut(&self, r: &'a mut RanimScene) -> Self::MutOutput {
437 r.timelines.get_mut(*self)
438 }
443}
444
445impl<'a, T: 'static> TimelineIndex<'a> for ItemId<T> {
446 type RefOutput = &'a ItemTimeline<T>;
447 type MutOutput = &'a mut ItemTimeline<T>;
448 fn timeline(&self, r: &'a RanimScene) -> Self::RefOutput {
449 r.timelines.get(**self).unwrap().get()
450 }
457 fn timeline_mut(&self, r: &'a mut RanimScene) -> Self::MutOutput {
458 r.timelines.get_mut(**self).unwrap().get_mut()
459 }
466}
467
468impl<'a, T: 'static, const N: usize> TimelineIndex<'a> for [&ItemId<T>; N] {
469 type RefOutput = [&'a ItemTimeline<T>; N];
470 type MutOutput = [&'a mut ItemTimeline<T>; N];
471 fn timeline(&self, r: &'a RanimScene) -> Self::RefOutput {
472 let mut timelines = r
474 .timelines()
475 .iter()
476 .enumerate()
477 .filter(|(id, _)| self.iter().any(|target_id| ***target_id == *id))
478 .collect_array::<N>()
479 .unwrap();
480 timelines.sort_by_key(|(id, _)| {
481 self.iter()
482 .position(|target_id| ***target_id == *id)
483 .unwrap()
484 });
485 timelines.map(|(_, timeline)| timeline.get())
486 }
487 fn timeline_mut(&self, r: &'a mut RanimScene) -> Self::MutOutput {
488 let mut timelines = r
490 .timelines_mut()
491 .iter_mut()
492 .enumerate()
493 .filter(|(id, _)| self.iter().any(|target_id| ***target_id == *id))
494 .collect_array::<N>()
495 .unwrap();
496 timelines.sort_by_key(|(id, _)| {
497 self.iter()
498 .position(|target_id| ***target_id == *id)
499 .unwrap()
500 });
501 timelines.map(|(_, timeline)| timeline.get_mut())
502 }
503}