Skip to main content

ranim_render/
setup.rs

1//! Reusable render configuration carried by a project.
2
3use std::sync::Arc;
4
5use bevy_app::{App, Plugin};
6use bevy_ecs::prelude::Resource;
7
8/// Deferred configuration for an independent render runtime.
9///
10/// Store this value in project resources and clone it into the argument of
11/// [`install_render_app`](crate::install_render_app). Creating or cloning a
12/// setup does not initialize a GPU. Its callback runs for each renderer after
13/// shared GPU resources and schedules have been installed.
14#[derive(Clone, Resource)]
15pub struct RenderSetup {
16    configure: Arc<dyn Fn(&mut App) + Send + Sync>,
17}
18
19impl RenderSetup {
20    /// Save repeatable configuration without running it.
21    pub fn new(configure: impl Fn(&mut App) + Send + Sync + 'static) -> Self {
22        Self {
23            configure: Arc::new(configure),
24        }
25    }
26}
27
28impl Plugin for RenderSetup {
29    fn build(&self, app: &mut App) {
30        (self.configure)(app);
31    }
32
33    fn is_unique(&self) -> bool {
34        false
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use std::sync::{
41        Arc,
42        atomic::{AtomicUsize, Ordering},
43    };
44
45    use bevy_app::SubApp;
46    use bevy_ecs::prelude::Resource;
47
48    use super::*;
49
50    #[derive(Resource)]
51    struct Configured(String);
52
53    #[test]
54    fn setup_is_deferred_and_reusable_across_render_apps() {
55        let calls = Arc::new(AtomicUsize::new(0));
56        let setup = RenderSetup::new({
57            let calls = Arc::clone(&calls);
58            let configuration = String::from("project configuration");
59            move |app| {
60                calls.fetch_add(1, Ordering::SeqCst);
61                app.insert_resource(Configured(configuration.clone()));
62            }
63        });
64        let cloned = setup.clone();
65        assert_eq!(calls.load(Ordering::SeqCst), 0);
66
67        for setup in [setup, cloned] {
68            let mut app = SubApp::new();
69            app.add_plugins(setup);
70            assert_eq!(
71                app.world().resource::<Configured>().0,
72                "project configuration"
73            );
74        }
75        assert_eq!(calls.load(Ordering::SeqCst), 2);
76    }
77}