ranim/
scene.rs

1//! Scene description types.
2//!
3//! These types describe *what* to render (scene metadata, output settings)
4//! rather than *how* to animate (which lives in `ranim-core`).
5
6use std::sync::Arc;
7
8use ranim_core::{RanimScene, SealedRanimScene};
9
10#[cfg(target_arch = "wasm32")]
11use wasm_bindgen::prelude::*;
12
13/// A scene descriptor bundling a constructor, config, and outputs.
14#[doc(hidden)]
15#[derive(Clone)]
16#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
17pub struct Scene {
18    /// Scene name
19    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
20    pub name: String,
21    /// Scene constructor
22    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
23    pub constructor: fn(&mut RanimScene),
24    /// Scene config
25    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
26    pub config: SceneConfig,
27    /// Scene outputs
28    #[cfg_attr(target_arch = "wasm32", wasm_bindgen(skip))]
29    pub outputs: Vec<Output>,
30}
31
32/// Scene config
33#[derive(Debug, Clone)]
34pub struct SceneConfig {
35    /// The clear color
36    pub clear_color: String,
37}
38
39impl Default for SceneConfig {
40    fn default() -> Self {
41        Self {
42            clear_color: "#333333ff".to_string(),
43        }
44    }
45}
46
47/// The output format of a scene
48#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
49pub enum OutputFormat {
50    /// H.264 in MP4 container (default, opaque)
51    #[default]
52    Mp4,
53    /// VP9 with alpha in WebM container (transparent)
54    Webm,
55    /// ProRes 4444 in MOV container (transparent)
56    Mov,
57    /// GIF (opaque, limited palette)
58    Gif,
59}
60
61impl std::fmt::Display for OutputFormat {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        match self {
64            Self::Mp4 => write!(f, "mp4"),
65            Self::Webm => write!(f, "webm"),
66            Self::Mov => write!(f, "mov"),
67            Self::Gif => write!(f, "gif"),
68        }
69    }
70}
71
72/// The output of a scene
73#[derive(Debug, Clone)]
74pub struct Output {
75    /// The width of the output texture in pixels.
76    pub width: u32,
77    /// The height of the output texture in pixels.
78    pub height: u32,
79    /// The frame rate of the output video.
80    pub fps: u32,
81    /// Whether to save the frames.
82    pub save_frames: bool,
83    /// The name of the video, uses scene's name by default.
84    ///
85    /// e.g. the output of name `my_video` will be outputed as `my_video_<width>x<height>_<fps>.mp4`.
86    pub name: Option<String>,
87    /// The directory to save the output.
88    ///
89    /// Can be relative (resolved from cwd) or absolute.
90    pub dir: String,
91    /// The output video format.
92    pub format: OutputFormat,
93}
94
95impl Default for Output {
96    fn default() -> Self {
97        Self {
98            width: 1920,
99            height: 1080,
100            fps: 60,
101            save_frames: false,
102            name: None,
103            dir: "./output".to_string(),
104            format: OutputFormat::default(),
105        }
106    }
107}
108
109// MARK: SceneConstructor
110// ANCHOR: SceneConstructor
111/// A scene constructor
112///
113/// It can be a simple fn pointer of `fn(&mut RanimScene)`,
114/// or any type implements `Fn(&mut RanimScene) + Send + Sync`.
115pub trait SceneConstructor: Send + Sync {
116    /// The construct logic
117    fn construct(&self, r: &mut RanimScene);
118
119    /// Use the constructor to build a [`SealedRanimScene`]
120    fn build_scene(&self) -> SealedRanimScene {
121        let mut scene = RanimScene::new();
122        self.construct(&mut scene);
123        scene.seal()
124    }
125}
126// ANCHOR_END: SceneConstructor
127
128impl<F: Fn(&mut RanimScene) + Send + Sync> SceneConstructor for F {
129    fn construct(&self, r: &mut RanimScene) {
130        self(r);
131    }
132}
133
134impl SceneConstructor for Arc<dyn SceneConstructor> {
135    fn construct(&self, r: &mut RanimScene) {
136        self.as_ref().construct(r)
137    }
138}