1 use core::controller::ControllerManager;
2 use core::render::Renderer;
3 use geometry::{Dimension};
4 use sdl2::event::{Event, WindowEvent};
5 use sdl2::keyboard::Keycode;
6 use sdl2::video::SwapInterval;
7 use sdl2::{EventPump, VideoSubsystem};
8 use sprites::SpriteManager;
9 use time::{Duration, Instant};
12 pub struct AppBuilder {
13 resolution: Dimension<u16>,
14 state: Option<Box<dyn AppState>>,
15 title: Option<String>,
19 pub fn with_resolution(mut self, width: u16, height: u16) -> Self {
20 self.resolution = Dimension { width, height };
24 pub fn with_state(mut self, state: Box<dyn AppState>) -> Self {
25 self.state = Some(state);
29 pub fn with_title(mut self, title: &str) -> Self {
30 self.title = Some(title.to_string());
34 pub fn build(self) -> Result<App, String> {
35 let context = sdl2::init().unwrap();
36 sdl2::image::init(sdl2::image::InitFlag::PNG)?;
37 let video = context.video()?;
38 //self.print_video_display_modes(&video);
43 self.resolution.width.into(),
44 self.resolution.height.into(),
48 // .fullscreen_desktop()
52 context.mouse().show_cursor(false);
54 let canvas = window.into_canvas().build().unwrap();
55 let sprites = SpriteManager::new(canvas.texture_creator());
56 let renderer = Renderer::new(canvas);
58 video.gl_set_swap_interval(SwapInterval::VSync)?;
60 let event_pump = context.event_pump()?;
66 states: vec!(self.state.unwrap()),
67 ctrl_man: ControllerManager::new(context.game_controller()?, context.haptic()?),
72 fn print_video_display_modes(&self, video: &VideoSubsystem) {
73 println!("video subsystem: {:?}", video);
74 println!("current_video_driver: {:?}", video.current_video_driver());
75 for display in 0..video.num_video_displays().unwrap() {
77 "=== display {} - {} ===",
79 video.display_name(display).unwrap()
82 " display_bounds: {:?}",
83 video.display_bounds(display).unwrap()
86 " num_display_modes: {:?}",
87 video.num_display_modes(display).unwrap()
90 " desktop_display_mode: {:?}",
91 video.desktop_display_mode(display).unwrap()
93 let current = video.current_display_mode(display).unwrap();
95 " current_display_mode: {:?}",
98 for idx in 0..video.num_display_modes(display).unwrap() {
99 let mode = video.display_mode(display, idx).unwrap();
102 if mode == current { "*" } else { " " },
108 println!("swap interval: {:?}", video.gl_get_swap_interval());
114 event_pump: EventPump,
115 sprites: SpriteManager,
116 states: Vec<Box<dyn AppState>>,
117 pub ctrl_man: ControllerManager,
121 #[allow(clippy::new_ret_no_self)]
122 pub fn new() -> AppBuilder {
126 pub fn load_sprites(&mut self, sprites: &[(&str, &str)]) {
127 for (name, file) in sprites {
128 self.sprites.load(name, file);
132 pub fn start(&mut self) {
133 let mut last_time = Instant::now();
135 self.states[0].enter(&self.ctrl_man);
138 if let Some(change) = self.handle_events() {
139 self.handle_state_change(change);
142 let duration = Instant::now() - last_time;
143 last_time = Instant::now();
145 self.ctrl_man.update(duration);
147 if let Some(state) = self.states.last_mut() {
148 if let Some(change) = state.update(duration) {
149 self.handle_state_change(change);
159 fn handle_state_change(&mut self, change: StateChange) {
161 StateChange::Push(mut state) => {
162 // if let Some(s) = self.states.last_mut() {
165 state.enter(&self.ctrl_man);
166 self.states.push(state);
168 StateChange::Pop => {
169 if let Some(mut s) = self.states.pop() {
173 StateChange::Exit => {
174 while let Some(mut s) = self.states.pop() {
181 fn handle_events(&mut self) -> Option<StateChange> {
182 for event in self.event_pump.poll_iter() {
183 self.ctrl_man.handle_event(&event);
187 keycode: Some(Keycode::Escape),
190 return Some(StateChange::Pop)
193 keycode: Some(Keycode::F11),
196 self.renderer.toggle_fullscreen();
199 win_event: WindowEvent::Resized(x, y),
202 println!("window resized({}, {})", x, y)
205 win_event: WindowEvent::Maximized,
208 println!("window maximized")
211 win_event: WindowEvent::Restored,
214 println!("window restored")
217 win_event: WindowEvent::Enter,
220 println!("window enter")
223 win_event: WindowEvent::Leave,
226 println!("window leave")
229 win_event: WindowEvent::FocusGained,
232 println!("window focus gained")
235 win_event: WindowEvent::FocusLost,
238 println!("window focus lost")
241 if let Some(state) = self.states.last_mut() {
242 if let Some(change) = state.handle_event(event) {
246 return Some(StateChange::Exit)
254 fn render(&mut self) {
255 self.renderer.clear();
256 self.states.last_mut().unwrap().render(&mut self.renderer, &self.sprites);
257 self.renderer.present();
261 pub enum StateChange {
262 Push(Box<dyn AppState>),
268 fn enter(&mut self, ctrl_man: &ControllerManager);
270 fn update(&mut self, dt: Duration) -> Option<StateChange>;
271 fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager);
272 fn handle_event(&mut self, event: Event) -> Option<StateChange>;