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