Skip to main content

ranim/
link_magic.rs

1//! Scene types for dylib / inventory registration and runtime use.
2use crate::{Output, OutputFormat, Scene, SceneConfig};
3use ranim_core::RanimScene;
4
5#[cfg(target_arch = "wasm32")]
6use wasm_bindgen::prelude::*;
7
8/// Static scene type for inventory registration
9#[doc(hidden)]
10pub struct StaticScene {
11    /// Scene name
12    pub name: &'static str,
13    /// Scene constructor
14    pub constructor: fn(&mut RanimScene),
15    /// Scene config
16    pub config: StaticSceneConfig,
17    /// Scene outputs
18    pub outputs: &'static [StaticOutput],
19}
20
21/// Static scene config for inventory registration
22#[doc(hidden)]
23pub struct StaticSceneConfig {
24    /// The clear color
25    pub clear_color: &'static str,
26}
27
28/// Static output for inventory registration
29#[doc(hidden)]
30pub struct StaticOutput {
31    /// The width of the output texture in pixels.
32    pub width: u32,
33    /// The height of the output texture in pixels.
34    pub height: u32,
35    /// The frame rate of the output video.
36    pub fps: u32,
37    /// Whether to save the frames.
38    pub save_frames: bool,
39    /// The name of the video, uses scene's name by default.
40    pub name: Option<&'static str>,
41    /// The basename template for the rendered output.
42    pub name_template: Option<&'static str>,
43    /// The directory to save the output.
44    pub dir: &'static str,
45    /// The output format
46    pub format: OutputFormat,
47}
48
49impl StaticOutput {
50    /// 1920x1080 60fps save_frames=false dir="./"
51    pub const DEFAULT: Self = Self {
52        width: 1920,
53        height: 1080,
54        fps: 60,
55        save_frames: false,
56        name: None,
57        name_template: None,
58        dir: "./output",
59        format: OutputFormat::Mp4,
60    };
61}
62
63// MARK: inventory + FFI
64
65pub use inventory;
66
67inventory::collect!(StaticScene);
68
69#[doc(hidden)]
70#[unsafe(no_mangle)]
71pub extern "C" fn get_scene(idx: usize) -> *const StaticScene {
72    inventory::iter::<StaticScene>()
73        .skip(idx)
74        .take(1)
75        .next()
76        .unwrap()
77}
78
79#[doc(hidden)]
80#[unsafe(no_mangle)]
81pub extern "C" fn scene_cnt() -> usize {
82    inventory::iter::<StaticScene>().count()
83}
84
85/// Return a scene with matched name
86#[cfg_attr(target_arch = "wasm32", wasm_bindgen)]
87pub fn find_scene(name: &str) -> Option<Scene> {
88    inventory::iter::<StaticScene>()
89        .find(|s| s.name == name)
90        .map(Scene::from)
91}
92
93// MARK: From impls (Static -> Owned)
94
95impl From<&StaticScene> for Scene {
96    fn from(s: &StaticScene) -> Self {
97        Self {
98            name: s.name.to_string(),
99            constructor: s.constructor,
100            config: SceneConfig::from(&s.config),
101            outputs: s.outputs.iter().map(Output::from).collect(),
102        }
103    }
104}
105
106impl From<&StaticSceneConfig> for SceneConfig {
107    fn from(c: &StaticSceneConfig) -> Self {
108        Self {
109            clear_color: c.clear_color.to_string(),
110        }
111    }
112}
113
114impl From<&StaticOutput> for Output {
115    fn from(o: &StaticOutput) -> Self {
116        Self {
117            width: o.width,
118            height: o.height,
119            fps: o.fps,
120            save_frames: o.save_frames,
121            name: o.name.map(|n| n.to_string()),
122            name_template: o.name_template.map(|n| n.to_string()),
123            dir: o.dir.to_string(),
124            format: o.format,
125        }
126    }
127}