1use std::ops::{Deref, DerefMut};
8
9use bevy_app::{App, PluginsState};
10use bevy_ecs::prelude::*;
11
12mod scene;
13pub use scene::{Output, OutputFormat, Scene, SceneConfig, SceneConstructor};
14
15#[cfg(any(
17 feature = "cmd-render",
18 all(target_family = "wasm", feature = "render")
19))]
20pub(crate) fn render_setup_of(app: &App) -> ranim_render::RenderSetup {
21 app.world()
22 .get_resource::<ranim_render::RenderSetup>()
23 .cloned()
24 .unwrap_or_else(|| {
25 ranim_render::RenderSetup::new(|_render_app| {
26 #[cfg(feature = "items")]
27 _render_app.add_plugins(ranim_items::RanimItemsPlugin);
28 })
29 })
30}
31
32#[derive(Resource, Default)]
34pub struct Scenes(Vec<Scene>);
35
36pub struct RanimApp(App);
44
45impl RanimApp {
46 pub fn into_inner(self) -> App {
48 self.0
49 }
50}
51
52impl Deref for RanimApp {
53 type Target = App;
54
55 fn deref(&self) -> &Self::Target {
56 &self.0
57 }
58}
59
60impl DerefMut for RanimApp {
61 fn deref_mut(&mut self) -> &mut Self::Target {
62 &mut self.0
63 }
64}
65
66pub trait RanimAppExt {
68 fn build(&mut self) -> RanimApp;
75}
76
77impl RanimAppExt for App {
78 fn build(&mut self) -> RanimApp {
79 assert_eq!(
80 self.plugins_state(),
81 PluginsState::Ready,
82 "plugins must be ready before building a RanimApp"
83 );
84 self.finish();
85 self.cleanup();
86 RanimApp(std::mem::take(self))
87 }
88}
89
90pub trait AppExt {
92 fn add_scene(&mut self, scene: Scene) -> &mut Self;
98
99 fn add_scenes(&mut self, scenes: impl IntoIterator<Item = Scene>) -> &mut Self {
106 for scene in scenes {
107 self.add_scene(scene);
108 }
109 self
110 }
111
112 fn scenes(&self) -> &[Scene];
114
115 fn scene(&self, name: &str) -> Option<Scene>;
117
118 fn first_scene(&self) -> Option<Scene> {
120 self.scenes().first().cloned()
121 }
122}
123
124impl AppExt for bevy_app::App {
125 fn add_scene(&mut self, scene: Scene) -> &mut Self {
126 let mut scenes = self.world_mut().get_resource_or_init::<Scenes>();
127 assert!(
128 !scenes.0.iter().any(|existing| existing.name == scene.name),
129 "scene `{}` is already registered",
130 scene.name,
131 );
132 scenes.0.push(scene);
133 self
134 }
135
136 fn scenes(&self) -> &[Scene] {
137 self.world()
138 .get_resource::<Scenes>()
139 .map(|scenes| scenes.0.as_slice())
140 .unwrap_or(&[])
141 }
142
143 fn scene(&self, name: &str) -> Option<Scene> {
144 self.scenes()
145 .iter()
146 .find(|scene| scene.name == name)
147 .cloned()
148 }
149}
150
151#[cfg(test)]
152mod tests;