1use crate::engine::Context;
11
12pub trait Scene: SceneAsAny + 'static {
21 fn on_enter(&mut self, _ctx: &mut Context) {}
23
24 fn on_exit(&mut self, _ctx: &mut Context) {}
26
27 fn on_pause(&mut self, _ctx: &mut Context) {}
29
30 fn on_resume(&mut self, _ctx: &mut Context) {}
32
33 fn update(&mut self, ctx: &mut Context);
35
36 fn render(&mut self, ctx: &mut Context);
38
39 fn handle_event(&mut self, _ctx: &mut Context, _event: &SceneEvent) {}
41}
42
43#[derive(Debug, Clone)]
45pub enum SceneEvent {
46 WindowResized { width: u32, height: u32 },
48 GainedFocus,
50 LostFocus,
52 Custom(String),
54}
55
56#[derive(Debug, Clone)]
62pub enum Transition {
63 None,
65 Fade { duration: f32, color: [f32; 4] },
67 Slide { duration: f32, direction: SlideDirection },
69}
70
71#[derive(Debug, Clone, Copy)]
72pub enum SlideDirection {
73 Left,
74 Right,
75 Up,
76 Down,
77}
78
79#[derive(Debug, Clone, Copy, PartialEq)]
85enum TransitionPhase {
86 Idle,
88 Out,
90 In,
92}
93
94pub struct SceneManager {
111 stack: Vec<Box<dyn Scene>>,
112 transition: Option<TransitionEffect>,
113 pending_push: Option<Box<dyn Scene>>,
115 pending_pop: bool,
117 pending_replace: Option<Box<dyn Scene>>,
119}
120
121#[derive(Debug)]
122struct TransitionEffect {
123 #[allow(dead_code)]
124 kind: Transition,
125 phase: TransitionPhase,
126 timer: f32,
127 half_duration: f32,
128}
129
130impl SceneManager {
131 pub fn new() -> Self {
133 Self {
134 stack: Vec::new(),
135 transition: None,
136 pending_push: None,
137 pending_pop: false,
138 pending_replace: None,
139 }
140 }
141
142 pub fn push<S: Scene>(&mut self, scene: S) {
144 match &self.transition {
145 Some(t) if t.phase != TransitionPhase::Idle => {
146 self.pending_push = Some(Box::new(scene));
148 return;
149 }
150 _ => {}
151 }
152
153 let mut fake_ctx = self.make_fake_ctx();
155 if let Some(current) = self.stack.last_mut() {
156 current.on_pause(&mut fake_ctx);
157 }
158
159 self.stack.push(Box::new(scene));
160 if let Some(top) = self.stack.last_mut() {
161 top.on_enter(&mut fake_ctx);
162 }
163 }
164
165 pub fn pop(&mut self) {
167 match &self.transition {
168 Some(t) if t.phase != TransitionPhase::Idle => {
169 self.pending_pop = true;
170 return;
171 }
172 _ => {}
173 }
174
175 let mut fake_ctx = self.make_fake_ctx();
176 if let Some(mut scene) = self.stack.pop() {
177 scene.on_exit(&mut fake_ctx);
178 }
179
180 if let Some(top) = self.stack.last_mut() {
182 top.on_resume(&mut fake_ctx);
183 }
184 }
185
186 pub fn replace<S: Scene>(&mut self, scene: S) {
188 match &self.transition {
189 Some(t) if t.phase != TransitionPhase::Idle => {
190 self.pending_replace = Some(Box::new(scene));
191 return;
192 }
193 _ => {}
194 }
195
196 let mut fake_ctx = self.make_fake_ctx();
197 if let Some(mut old) = self.stack.pop() {
198 old.on_exit(&mut fake_ctx);
199 }
200
201 self.stack.push(Box::new(scene));
202 if let Some(top) = self.stack.last_mut() {
203 top.on_enter(&mut fake_ctx);
204 }
205 }
206
207 pub fn push_with_transition<S: Scene>(&mut self, scene: S, transition: Transition) {
209 self.start_transition(transition);
210 self.pending_push = Some(Box::new(scene));
211 }
212
213 pub fn pop_with_transition(&mut self, transition: Transition) {
215 self.start_transition(transition);
216 self.pending_pop = true;
217 }
218
219 pub fn current(&self) -> Option<&dyn Scene> {
221 self.stack.last().map(|s| s.as_ref())
222 }
223
224 pub fn current_mut(&mut self) -> Option<&mut dyn Scene> {
226 self.stack.last_mut().map(|s| s.as_mut())
227 }
228
229 pub fn find<S: Scene>(&self) -> Option<&S> {
231 for scene in &self.stack {
232 if let Some(s) = scene.as_ref().as_any().downcast_ref::<S>() {
233 return Some(s);
234 }
235 }
236 None
237 }
238
239 pub fn depth(&self) -> usize {
241 self.stack.len()
242 }
243
244 pub fn is_empty(&self) -> bool {
246 self.stack.is_empty()
247 }
248
249 pub fn update(&mut self, ctx: &mut Context) {
251 let mut trans_opt = self.transition.take();
255 if let Some(trans) = &mut trans_opt {
256 trans.timer += ctx.time.delta() as f32;
257 match trans.phase {
258 TransitionPhase::Out => {
259 if trans.timer >= trans.half_duration {
260 self.execute_pending(ctx);
262 trans.phase = TransitionPhase::In;
263 trans.timer = 0.0;
264 }
265 }
266 TransitionPhase::In => {
267 if trans.timer >= trans.half_duration {
268 trans_opt = None;
271 }
272 }
273 TransitionPhase::Idle => {}
274 }
275 }
276 self.transition = trans_opt;
277
278 if let Some(top) = self.stack.last_mut() {
280 top.update(ctx);
281 }
282 }
283
284 pub fn render(&mut self, ctx: &mut Context) {
286 if let Some(trans) = &self.transition {
289 match trans.phase {
290 TransitionPhase::Out => {
291 if let Some(scene) = self.stack.last_mut() {
292 scene.render(ctx);
293 }
294 self.render_transition_overlay(ctx, trans, false);
295 }
296 TransitionPhase::In => {
297 if let Some(scene) = self.stack.last_mut() {
298 scene.render(ctx);
299 }
300 self.render_transition_overlay(ctx, trans, true);
301 }
302 TransitionPhase::Idle => {}
303 }
304 } else if let Some(top) = self.stack.last_mut() {
305 top.render(ctx);
306 }
307 }
308
309 fn start_transition(&mut self, kind: Transition) {
310 let half_duration = match &kind {
311 Transition::None => 0.0,
312 Transition::Fade { duration, .. } => duration / 2.0,
313 Transition::Slide { duration, .. } => duration / 2.0,
314 };
315 self.transition = Some(TransitionEffect {
316 kind,
317 phase: TransitionPhase::Out,
318 timer: 0.0,
319 half_duration,
320 });
321 }
322
323 fn execute_pending(&mut self, ctx: &mut Context) {
324 if let Some(scene) = self.pending_push.take() {
325 if let Some(current) = self.stack.last_mut() {
326 current.on_pause(ctx);
327 }
328 self.stack.push(scene);
329 if let Some(top) = self.stack.last_mut() {
330 top.on_enter(ctx);
331 }
332 }
333
334 if self.pending_pop {
335 self.pending_pop = false;
336 if let Some(mut scene) = self.stack.pop() {
337 scene.on_exit(ctx);
338 }
339 if let Some(top) = self.stack.last_mut() {
340 top.on_resume(ctx);
341 }
342 }
343
344 if let Some(scene) = self.pending_replace.take() {
345 if let Some(mut old) = self.stack.pop() {
346 old.on_exit(ctx);
347 }
348 self.stack.push(scene);
349 if let Some(top) = self.stack.last_mut() {
350 top.on_enter(ctx);
351 }
352 }
353 }
354
355 fn render_transition_overlay(&self, _ctx: &mut Context, trans: &TransitionEffect, _is_in: bool) {
356 let _ = (trans, _is_in); }
360
361 fn make_fake_ctx(&self) -> Context {
364 Context::default()
365 }
366}
367
368pub trait SceneAsAny {
377 fn as_any(&self) -> &dyn std::any::Any;
378}
379
380impl<S: Scene + 'static> SceneAsAny for S {
381 fn as_any(&self) -> &dyn std::any::Any { self }
382}