1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::*;

pub use helper::*;

#[cfg(all(not(target_arch = "wasm32"), not(feature="winit"), not(feature="tao")))]
mod helper {
    use super::*;

    pub fn game_loop<G, U, R>(game: G, updates_per_second: u32, max_frame_time: f64, mut update: U, mut render: R) -> GameLoop<G, Time, ()>
        where U: FnMut(&mut GameLoop<G, Time, ()>),
              R: FnMut(&mut GameLoop<G, Time, ()>),
    {
        let mut game_loop = GameLoop::new(game, updates_per_second, max_frame_time, ());

        while game_loop.next_frame(&mut update, &mut render) {}

        game_loop
    }
}

#[cfg(all(target_arch = "wasm32", not(feature = "winit")))]
mod helper {
    use super::*;
    use web_sys::window;
    use wasm_bindgen::JsCast;
    use wasm_bindgen::closure::Closure;

    pub fn game_loop<G, U, R>(game: G, updates_per_second: u32, max_frame_time: f64, update: U, render: R)
        where G: 'static,
              U: FnMut(&mut GameLoop<G, Time, ()>) + 'static,
              R: FnMut(&mut GameLoop<G, Time, ()>) + 'static,
    {
        let game_loop = GameLoop::new(game, updates_per_second, max_frame_time, ());

        animation_frame(game_loop, update, render);
    }

    fn animation_frame<G, U, R>(mut g: GameLoop<G, Time, ()>, mut update: U, mut render: R)
        where G: 'static,
              U: FnMut(&mut GameLoop<G, Time, ()>) + 'static,
              R: FnMut(&mut GameLoop<G, Time, ()>) + 'static,
    {
        if g.next_frame(&mut update, &mut render) {
            let next_frame = move || animation_frame(g, update, render);
            let closure = Closure::once_into_js(next_frame);
            let js_func = closure.as_ref().unchecked_ref();

            window().unwrap().request_animation_frame(js_func).unwrap();
        }
    }
}

#[cfg(feature="winit")]
mod helper {
    use std::sync::Arc;
    use super::*;
    use winit::event::{Event, WindowEvent};
    use winit::event_loop::{ControlFlow, EventLoop};
    use winit::window::Window;

    pub use winit;

    pub fn game_loop<G, U, R, H, T>(event_loop: EventLoop<T>, window: Arc<Window>, game: G, updates_per_second: u32, max_frame_time: f64, mut update: U, mut render: R, mut handler: H) -> !
        where G: 'static,
              U: FnMut(&mut GameLoop<G, Time, Arc<Window>>) + 'static,
              R: FnMut(&mut GameLoop<G, Time, Arc<Window>>) + 'static,
              H: FnMut(&mut GameLoop<G, Time, Arc<Window>>, &Event<'_, T>) + 'static,
              T: 'static,
    {
        let mut game_loop = GameLoop::new(game, updates_per_second, max_frame_time, window);

        event_loop.run(move |event, _, control_flow| {
            *control_flow = ControlFlow::Poll;

            // Forward events to existing handlers.
            handler(&mut game_loop, &event);

            match event {
                Event::RedrawRequested(_) => {
                    if !game_loop.next_frame(&mut update, &mut render) {
                        *control_flow = ControlFlow::Exit;
                    }
                },
                Event::MainEventsCleared => {
                    game_loop.window.request_redraw();
                },
                Event::WindowEvent { event: WindowEvent::Occluded(occluded), .. } => {
                    game_loop.window_occluded = occluded;
                },
                _ => {},
            }
        })
    }
}

#[cfg(feature = "tao")]
mod helper {
    use super::*;
    use tao::event::Event;
    use tao::event_loop::{ControlFlow, EventLoop};
    use tao::window::Window;
    use std::sync::Arc;

    pub use tao;

    pub fn game_loop<G, U, R, H, T>(event_loop: EventLoop<T>, window: Arc<Window>, game: G, updates_per_second: u32, max_frame_time: f64, mut update: U, mut render: R, mut handler: H) -> !
        where G: 'static,
              U: FnMut(&mut GameLoop<G, Time, Arc<Window>>) + 'static,
              R: FnMut(&mut GameLoop<G, Time, Arc<Window>>) + 'static,
              H: FnMut(&mut GameLoop<G, Time, Arc<Window>>, &Event<'_, T>) + 'static,
              T: 'static,
    {
        let mut game_loop = GameLoop::new(game, updates_per_second, max_frame_time, window);

        event_loop.run(move |event, _, control_flow| {
            *control_flow = ControlFlow::Poll;

            // Forward events to existing handlers.
            handler(&mut game_loop, &event);

            match event {
                Event::RedrawRequested(_) => {
                    if !game_loop.next_frame(&mut update, &mut render) {
                        *control_flow = ControlFlow::Exit;
                    }
                },
                Event::MainEventsCleared => {
                    game_loop.window.request_redraw();
                },
                _ => {},
            }
        })
    }
}