1use futures::prelude::*;
2
3scoped_tls::scoped_thread_local! { static mut WITH_FRAMEBUFFER: for<'a> &'a mut (dyn 'a + FnMut(&mut dyn FnMut(&mut ugli::Framebuffer))) }
4
5pub fn with_current_framebuffer<T>(
6 window: &geng_window::Window,
7 f: impl FnOnce(&mut ugli::Framebuffer<'_>) -> T,
8) -> T {
9 if WITH_FRAMEBUFFER.is_set() {
10 let mut value = None::<T>;
11 let mut f = Some(f);
12 WITH_FRAMEBUFFER.with(|with_framebuffer| {
13 with_framebuffer(&mut |framebuffer| value = Some(f.take().unwrap()(framebuffer)))
14 });
15 value.expect("LUL")
16 } else {
17 window.with_framebuffer(f)
18 }
19}
20
21pub trait ActiveState {
22 fn draw(&mut self, framebuffer: &mut ugli::Framebuffer);
23}
24
25impl<'a, T: ActiveState + ?Sized> ActiveState for &'a mut T {
26 fn draw(&mut self, framebuffer: &mut ugli::Framebuffer) {
27 (**self).draw(framebuffer)
28 }
29}
30
31impl<T: ActiveState + ?Sized> ActiveState for Box<T> {
32 fn draw(&mut self, framebuffer: &mut ugli::Framebuffer) {
33 (**self).draw(framebuffer)
34 }
35}
36
37pub trait Transition {
38 fn finished(&self) -> bool;
39 fn draw(
40 &mut self,
41 from: &mut dyn FnMut(&mut ugli::Framebuffer),
42 to: &mut dyn FnMut(&mut ugli::Framebuffer),
43 framebuffer: &mut ugli::Framebuffer,
44 );
45}
46
47pub struct StateResult<'a, T> {
48 pub value: T,
49 pub active_state: Box<dyn ActiveState + 'a>,
50}
51
52pub async fn transition<T>(
53 window: &geng_window::Window,
54 from: &mut dyn ActiveState,
55 transition: &mut dyn Transition,
56 into: impl Future<Output = T>,
57) -> T {
58 let mut into = std::pin::pin!(into);
59 std::future::poll_fn(|cx| {
60 if transition.finished() {
61 into.as_mut().poll(cx)
62 } else {
63 with_current_framebuffer(window, |actual_framebuffer| {
64 WITH_FRAMEBUFFER.set(
65 &mut |with_framebuffer: &mut dyn FnMut(&mut ugli::Framebuffer)| {
66 transition.draw(
67 &mut |f| from.draw(f),
68 with_framebuffer,
69 actual_framebuffer,
70 );
71 },
72 || into.as_mut().poll(cx),
73 )
74 })
75 }
76 })
77 .await
78}