penguin_app/
application.rs

1use super::ecs::*;
2use anyhow::*;
3
4use winit::event::WindowEvent;
5use winit::event::{ElementState, Event, VirtualKeyCode};
6use winit::event_loop::{ControlFlow, EventLoop};
7
8use crate::config::AppConfig;
9
10
11pub struct App {
12    pub event_loop: Option<EventLoop<()>>,
13    //
14    world: World,
15    resources: Resources,
16    //
17    startup_schedule: Schedule,
18    run_schedule: Schedule,
19    shutdown_schedule: Schedule,
20}
21impl App {
22    pub fn builder(config: AppConfig) -> builder::AppBuilder {
23        builder::AppBuilder::builder(config)
24    }
25
26    pub fn run(mut self) -> Result<()> {
27        self.startup_schedule
28            .execute(&mut self.world, &mut self.resources);
29
30        let event_loop = self.event_loop.take().unwrap();
31        self.run_loop(event_loop)
32    }
33
34    pub fn run_loop(mut self, event_loop: EventLoop<()>) -> Result<()> {
35        event_loop.run(move |event, _, control_flow| {
36            let _ = &self;
37            *control_flow = ControlFlow::Poll;
38
39            match event {
40                // Window events ------------
41                Event::WindowEvent { event, .. } => match event {
42                    WindowEvent::CloseRequested => {
43                        log::info!("Close requested, closing...");
44                        *control_flow = ControlFlow::Exit;
45                    }
46                    WindowEvent::KeyboardInput { input, .. } => {
47                        match (input.virtual_keycode, input.state) {
48                            (Some(VirtualKeyCode::Escape), ElementState::Pressed) => {
49                                *control_flow = ControlFlow::Exit
50                            }
51                            _ => {
52                                let input_events_resource =
53                                    self.resources.get_mut::<super::input::InputEvents>();
54                                input_events_resource.unwrap().update(input);
55                            }
56                        }
57                    }
58                    _ => {}
59                },
60                // Other events ------------
61                Event::MainEventsCleared => {
62                    self.run_schedule
63                        .execute(&mut self.world, &mut self.resources);
64                }
65                Event::RedrawRequested(_window_id) => {}
66                Event::LoopDestroyed => {
67                    self.shutdown_schedule
68                        .execute(&mut self.world, &mut self.resources);
69                }
70                _ => (),
71            }
72        });
73    }
74}
75
76
77pub mod builder {
78    use super::*;
79    use super::super::window;
80    use super::super::input;
81    use super::super::logger;
82
83    use crate::config::AppConfig;
84
85    pub struct AppBuilder {
86        event_loop: EventLoop<()>,
87        //
88        world: World,
89        resources: Resources,
90        startup_steps: Vec<Step>,
91        run_steps: Vec<Step>,
92        shutdown_steps: Vec<Step>,
93    }
94
95    impl AppBuilder {
96        pub fn builder(config: AppConfig) -> Self {
97
98            logger::init_logger(config.logger_config.clone()).expect("Couldn't init logger");
99
100
101            let event_loop = winit::event_loop::EventLoop::new();
102
103            let mut resources = Resources::default();
104            resources.insert(window::Window::new(
105                &event_loop,
106                config.clone().window_config,
107                config.logger_config.debug_message_severity.clone()
108            ));
109            log::trace!("Window resource created");
110
111
112            let builder = Self {
113                event_loop,
114                world: World::default(),
115                resources,
116                startup_steps: Vec::new(),
117                run_steps: Vec::new(),
118                shutdown_steps: Vec::new(),
119            };
120
121            builder.add_plugin(input::InputPlugin)
122        }
123
124        pub fn add_startup_steps(mut self, steps: Vec<Step>) -> Self {
125            self.startup_steps.extend(steps.into_iter());
126            self
127        }
128
129        pub fn add_run_steps(mut self, steps: Vec<Step>) -> Self {
130            self.run_steps.extend(steps.into_iter());
131            self
132        }
133
134        pub fn add_shutdown_steps(mut self, steps: Vec<Step>) -> Self {
135            self.shutdown_steps.extend(steps.into_iter());
136            self
137        }
138
139        #[allow(unused)]
140        pub fn insert_resource<T: 'static>(mut self, resource: T) -> Self
141        {
142            self.resources.insert(resource);
143            self
144        }
145
146        pub fn add_plugin<T: Plugin>(mut self, mut plugin: T) -> Self {
147            let startup_steps = plugin.startup(&mut self.resources);
148            self = self.add_startup_steps(startup_steps);
149            self = self.add_run_steps(T::run());
150            self = self.add_shutdown_steps(T::shutdown());
151            self
152        }
153
154        pub fn run(self) -> Result<()> {
155            let startup_schedule = Schedule::from(self.startup_steps);
156            let run_schedule = Schedule::from(self.run_steps);
157            let shutdown_schedule = Schedule::from(self.shutdown_steps);
158
159            let app = super::App {
160                event_loop: Some(self.event_loop),
161                world: self.world,
162                resources: self.resources,
163
164                startup_schedule,
165                run_schedule,
166                shutdown_schedule,
167            };
168
169            app.run()
170        }
171
172        pub fn build(self) -> super::App {
173            let startup_schedule = Schedule::from(self.startup_steps);
174            let run_schedule = Schedule::from(self.run_steps);
175            let shutdown_schedule = Schedule::from(self.shutdown_steps);
176
177            super::App {
178                event_loop: Some(self.event_loop),
179                world: self.world,
180                resources: self.resources,
181
182                startup_schedule,
183                run_schedule,
184                shutdown_schedule,
185            }
186        }
187    }
188}