Skip to main content

euv_engine/scene/
impl.rs

1use super::*;
2
3/// Implements static scene creation for `SceneManager`.
4impl SceneManager {
5    /// Creates a new `SceneRc` wrapping the given scene in a reference-counted cell.
6    ///
7    /// # Arguments
8    ///
9    /// - `T` - The concrete scene type implementing `Scene`.
10    ///
11    /// # Returns
12    ///
13    /// - `SceneRc` - The wrapped scene.
14    pub fn create_scene<T>(scene: T) -> SceneRc
15    where
16        T: Scene + 'static,
17    {
18        Rc::new(RefCell::new(scene))
19    }
20}
21
22/// Implements scene registration and lifecycle management for `SceneManager`.
23impl SceneManager {
24    /// Registers a scene under the given name.
25    ///
26    /// # Arguments
27    ///
28    /// - `String` - The name to register the scene under.
29    /// - `SceneRc` - The scene to register.
30    pub fn register(&mut self, name: String, scene: SceneRc) {
31        self.get_mut_scenes().insert(name, scene);
32    }
33
34    /// Unregisters and removes the scene with the given name.
35    ///
36    /// # Arguments
37    ///
38    /// - `N: AsRef<str>` - The name of the scene to remove.
39    pub fn unregister<N>(&mut self, name: N)
40    where
41        N: AsRef<str>,
42    {
43        self.get_mut_scenes().remove(name.as_ref());
44    }
45
46    /// Transitions to the scene with the given name.
47    ///
48    /// Calls `on_exit` on the current scene and `on_enter` on the new scene.
49    /// Returns `false` if no scene with the given name is registered.
50    ///
51    /// # Arguments
52    ///
53    /// - `N: AsRef<str>` - The name of the scene to switch to.
54    ///
55    /// # Returns
56    ///
57    /// - `bool` - True if the transition was successful.
58    pub fn switch_to<N>(&mut self, name: N) -> bool
59    where
60        N: AsRef<str>,
61    {
62        let name_ref: &str = name.as_ref();
63        if !self.get_scenes().contains_key(name_ref) {
64            return false;
65        }
66        let current_name: Option<String> = self.get_mut_current_scene_name().clone();
67        if let Some(name) = current_name.as_ref()
68            && let Some(current_scene) = self.get_scenes().get(name)
69        {
70            current_scene.borrow_mut().on_exit();
71        }
72        self.set_current_scene_name(Some(name_ref.to_string()));
73        if let Some(new_scene) = self.get_scenes().get(name_ref) {
74            new_scene.borrow_mut().on_enter();
75        }
76        true
77    }
78
79    /// Requests a deferred scene transition to be applied on the next update.
80    ///
81    /// # Arguments
82    ///
83    /// - `String` - The name of the scene to switch to.
84    pub fn request_transition(&mut self, name: String) {
85        self.set_pending_scene_name(Some(name));
86    }
87
88    /// Processes a pending scene transition if one was requested.
89    pub fn process_pending_transition(&mut self) {
90        let Some(name) = self.get_mut_pending_scene_name().take() else {
91            return;
92        };
93        self.switch_to(&name);
94    }
95
96    /// Calls `on_update` on the current scene.
97    ///
98    /// # Arguments
99    ///
100    /// - `f64` - The delta time in seconds.
101    pub fn update(&mut self, delta_time: f64) {
102        self.process_pending_transition();
103        let current_name: Option<String> = self.get_mut_current_scene_name().clone();
104        let Some(current_name) = current_name.as_ref() else {
105            return;
106        };
107        let Some(scene) = self.get_scenes().get(current_name) else {
108            return;
109        };
110        scene.borrow_mut().on_update(delta_time);
111    }
112
113    /// Calls `on_render` on the current scene, recording into the shared draw list.
114    ///
115    /// The manager's reusable `DrawList` is cleared, filled by the scene, and
116    /// left populated for the caller to replay (e.g. via
117    /// `CanvasRenderer::replay`). Reusing the list avoids per-frame allocation.
118    ///
119    /// # Arguments
120    ///
121    /// - `&CanvasRenderingContext2d` - The canvas rendering context used to replay
122    ///   the recorded commands.
123    pub fn render(&mut self, context: &CanvasRenderingContext2d) {
124        let Some(current_name) = self.try_get_current_scene_name().as_ref() else {
125            return;
126        };
127        // Clone the `Rc` so the immutable borrow of the scenes map ends before
128        // we mutably borrow the draw list.
129        let Some(scene) = self.get_scenes().get(current_name).cloned() else {
130            return;
131        };
132        self.get_mut_draw_list().clear();
133        {
134            let draw_list: &mut DrawList = self.get_mut_draw_list();
135            scene.borrow().on_render(draw_list);
136        }
137        CanvasRenderer::replay_context(context, self.get_draw_list());
138    }
139
140    /// Returns whether a scene with the given name is registered.
141    ///
142    /// # Arguments
143    ///
144    /// - `N: AsRef<str>` - The scene name to check.
145    ///
146    /// # Returns
147    ///
148    /// - `bool` - True if the scene is registered.
149    pub fn has_scene<N>(&self, name: N) -> bool
150    where
151        N: AsRef<str>,
152    {
153        self.get_scenes().contains_key(name.as_ref())
154    }
155
156    /// Returns the name of the currently active scene.
157    ///
158    /// # Returns
159    ///
160    /// - `Option<&str>` - The current scene name, or `None`.
161    pub fn current_name(&self) -> Option<&str> {
162        self.try_get_current_scene_name().as_deref()
163    }
164}
165
166/// Implements `Default` for `SceneManager` as a new empty manager.
167impl Default for SceneManager {
168    fn default() -> SceneManager {
169        SceneManager::new()
170    }
171}