X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=src%2Fcore%2Fapp.rs;h=18be50c84e7a9291adc159cfc858ff85df926715;hb=3af74c40c83bd8e5691bff3dc31f5cfd5ae9a73d;hp=f6adba046d0d64f4885d68b6cebf3f05d2282ce7;hpb=3d049b501751d825314db31b7f89d607eaae3e70;p=kaka%2Frust-sdl-test.git diff --git a/src/core/app.rs b/src/core/app.rs index f6adba0..18be50c 100644 --- a/src/core/app.rs +++ b/src/core/app.rs @@ -1,34 +1,31 @@ use boll::*; -use common::{Point2D, Rect}; +use common::{Point, Dimension}; +use core::controller::ControllerManager; +use core::render::Renderer; use point; // defined in common, but loaded from main... use rand::Rng; use sdl2::event::{Event, WindowEvent}; -use sdl2::gfx::primitives::DrawRenderer; use sdl2::keyboard::Keycode; -use sdl2::pixels::Color; use sdl2::rect::Rect as SDLRect; -use sdl2::render::{BlendMode, Canvas}; -use sdl2::video::{FullscreenType, SwapInterval, Window}; +use sdl2::video::SwapInterval; use sdl2::{EventPump, VideoSubsystem}; use sprites::SpriteManager; use std::f32::consts::PI; -use time::PreciseTime; - -pub type Nanoseconds = u64; +use time::{Duration, Instant, prelude::*}; const FPS: u32 = 60; const NS_PER_FRAME: u32 = 1_000_000_000 / FPS; #[derive(Default)] pub struct AppBuilder { - resolution: Rect, + resolution: Dimension, state: Option>, title: Option, } impl AppBuilder { pub fn with_resolution(mut self, width: u16, height: u16) -> Self { - self.resolution = Rect { width, height }; + self.resolution = Dimension { width, height }; self } @@ -46,8 +43,7 @@ impl AppBuilder { let context = sdl2::init().unwrap(); sdl2::image::init(sdl2::image::InitFlag::PNG)?; let video = context.video()?; - - self.print_video_display_modes(&video); + //self.print_video_display_modes(&video); let window = video .window( @@ -63,26 +59,25 @@ impl AppBuilder { .unwrap(); context.mouse().show_cursor(false); - let mut canvas = window.into_canvas().build().unwrap(); - canvas.set_blend_mode(BlendMode::Add); - canvas.set_draw_color(Color::RGB(0, 0, 0)); - canvas.clear(); - canvas.present(); + let canvas = window.into_canvas().build().unwrap(); + let sprites = SpriteManager::new(canvas.texture_creator()); + let screen = canvas.output_size().unwrap(); + let renderer = Renderer::new(canvas); video.gl_set_swap_interval(SwapInterval::VSync)?; let event_pump = context.event_pump()?; - let sprites = SpriteManager::new(canvas.texture_creator()); - let screen = canvas.output_size().unwrap(); Ok(App { - canvas, + renderer, event_pump, sprites, - state: self.state.unwrap_or_else(|| Box::new(ActiveState::new(screen))), + states: vec!(self.state.unwrap_or_else(|| Box::new(ActiveState::new(screen)))), + ctrl_man: ControllerManager::new(context.joystick()?, context.haptic()?), }) } + #[allow(dead_code)] fn print_video_display_modes(&self, video: &VideoSubsystem) { println!("video subsystem: {:?}", video); println!("current_video_driver: {:?}", video.current_video_driver()); @@ -124,10 +119,11 @@ impl AppBuilder { } pub struct App { - pub canvas: Canvas, - pub event_pump: EventPump, - pub sprites: SpriteManager, - pub state: Box, + renderer: Renderer, + event_pump: EventPump, + sprites: SpriteManager, + states: Vec>, + pub ctrl_man: ControllerManager, } impl App { @@ -143,57 +139,70 @@ impl App { } pub fn start(&mut self) { - let mut frame_count: u64 = 0; - let mut fps_time = PreciseTime::now(); - let mut last_time = PreciseTime::now(); + let mut last_time = Instant::now(); - 'running: loop { - if let Err(_) = self.handle_events() { - break 'running; + self.states[0].enter(&self.ctrl_man); + + loop { + if let Some(change) = self.handle_events() { + self.handle_state_change(change); } - let duration = - last_time.to(PreciseTime::now()).num_nanoseconds().unwrap() as Nanoseconds; - last_time = PreciseTime::now(); - self.state.update(duration); + let duration = Instant::now() - last_time; + last_time = Instant::now(); - self.render(); + self.ctrl_man.update(duration); - frame_count += 1; - if frame_count == FPS as u64 { - let duration = fps_time.to(PreciseTime::now()).num_nanoseconds().unwrap() as f64 - / 1_000_000_000.0; - println!("fps: {}", frame_count as f64 / duration); - frame_count = 0; - fps_time = PreciseTime::now(); - } + if let Some(state) = self.states.last_mut() { + if let Some(change) = state.update(duration) { + self.handle_state_change(change); + } + } else { + break; + } + + self.render(); } + } - self.state.leave(); + fn handle_state_change(&mut self, change: StateChange) { + match change { + StateChange::Push(mut state) => { + // if let Some(s) = self.states.last_mut() { + // s.pause(); + // } + state.enter(&mut self.ctrl_man); + self.states.push(state); + } + StateChange::Pop => { + if let Some(mut s) = self.states.pop() { + s.leave(); + } + } + StateChange::Exit => { + while let Some(mut s) = self.states.pop() { + s.leave(); + } + } + } } - fn handle_events(&mut self) -> Result<(), ()> { + fn handle_events(&mut self) -> Option { for event in self.event_pump.poll_iter() { + self.ctrl_man.handle_event(&event); match event { Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { - return Err(()) + return Some(StateChange::Pop) } Event::KeyDown { keycode: Some(Keycode::F11), .. } => { - match self.canvas.window().fullscreen_state() { - FullscreenType::Off => self - .canvas - .window_mut() - .set_fullscreen(FullscreenType::Desktop), - _ => self.canvas.window_mut().set_fullscreen(FullscreenType::Off), - } - .unwrap(); + self.renderer.toggle_fullscreen(); } Event::Window { win_event: WindowEvent::Resized(x, y), @@ -237,32 +246,44 @@ impl App { } => { println!("window focus lost") } - _ => self.state.on_event(event), + _ => { + if let Some(state) = self.states.last_mut() { + return state.handle_event(event) + } else { + return Some(StateChange::Exit) + } + }, } } - Ok(()) + None } fn render(&mut self) { - self.canvas.set_draw_color(Color::RGB(0, 0, 0)); - self.canvas.clear(); - self.state.render(&mut self.canvas, &mut self.sprites); - self.canvas.present(); + self.renderer.clear(); + self.states.last_mut().unwrap().render(&mut self.renderer, &mut self.sprites); + self.renderer.present(); } } +pub enum StateChange { + Push(Box), + Pop, + Exit, +} + pub trait AppState { - fn update(&mut self, dt: Nanoseconds); - fn render(&mut self, canvas: &mut Canvas, sprites: &mut SpriteManager); - fn leave(&self); - fn on_event(&mut self, event: Event); + fn enter(&mut self, ctrl_man: &ControllerManager); + fn leave(&mut self); + fn update(&mut self, dt: Duration) -> Option; + fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager); + fn handle_event(&mut self, event: Event) -> Option; } type Bollar = Vec>; #[derive(Default)] pub struct ActiveState { - screen: Rect, + screen: Dimension, bolls: Bollar, boll_size: u32, mario_angle: f64, @@ -273,7 +294,7 @@ impl ActiveState { ActiveState { bolls: Bollar::new(), boll_size: 1, - screen: Rect::from(screen), + screen: Dimension::from(screen), ..Default::default() } } @@ -304,19 +325,23 @@ impl ActiveState { } impl AppState for ActiveState { - fn update(&mut self, dt: Nanoseconds) { + fn enter(&mut self, _ctrl_man: &ControllerManager) {} + + fn update(&mut self, dt: Duration) -> Option { for b in &mut self.bolls { b.update(); } match dt { - ns if ns < (NS_PER_FRAME - 90_0000) as u64 => self.change_boll_count(100), - ns if ns > (NS_PER_FRAME + 90_0000) as u64 => self.change_boll_count(-100), + ns if ns < (NS_PER_FRAME - 90_0000).nanoseconds() => self.change_boll_count(100), + ns if ns > (NS_PER_FRAME + 90_0000).nanoseconds() => self.change_boll_count(-100), _ => {} } + + None } - fn render(&mut self, canvas: &mut Canvas, sprites: &mut SpriteManager) { + fn render(&mut self, renderer: &mut Renderer, sprites: &SpriteManager) { /* draw square of blocks */ { let blocks = 20; let size = 32; @@ -326,15 +351,14 @@ impl AppState for ActiveState { ); let block = sprites.get("block"); for i in 0..blocks { - canvas - .copy( + renderer + .blit( block, None, SDLRect::new((i) * size + offset.x, offset.y, size as u32, size as u32), - ) - .unwrap(); - canvas - .copy( + ); + renderer + .blit( block, None, SDLRect::new( @@ -343,10 +367,9 @@ impl AppState for ActiveState { size as u32, size as u32, ), - ) - .unwrap(); - canvas - .copy( + ); + renderer + .blit( block, None, SDLRect::new( @@ -355,10 +378,9 @@ impl AppState for ActiveState { size as u32, size as u32, ), - ) - .unwrap(); - canvas - .copy( + ); + renderer + .blit( block, None, SDLRect::new( @@ -367,8 +389,7 @@ impl AppState for ActiveState { size as u32, size as u32, ), - ) - .unwrap(); + ); } } @@ -381,8 +402,8 @@ impl AppState for ActiveState { let radius = 110.0 + size as f32 * 0.5; let angle = (self.mario_angle as f32 - 90.0) * PI / 180.0; let offset2 = point!((angle.cos() * radius) as i32, (angle.sin() * radius) as i32); - canvas - .copy_ex( + renderer + .blit_ex( sprites.get("mario"), None, SDLRect::new( @@ -395,37 +416,28 @@ impl AppState for ActiveState { sdl2::rect::Point::new(size / 2, size / 2), false, false, - ) - .unwrap(); + ); self.mario_angle = (self.mario_angle + 1.0) % 360.0; } /* draw circles and ellipses*/ { let p = point!((self.screen.width / 2) as i16, (self.screen.height / 2) as i16); - canvas - .circle(p.x, p.y, 100, Color::RGB(255, 255, 255)) - .unwrap(); - canvas - .aa_circle(p.x, p.y, 110, Color::RGB(255, 255, 255)) - .unwrap(); - canvas - .ellipse(p.x, p.y, 50, 100, Color::RGB(255, 255, 255)) - .unwrap(); - canvas - .aa_ellipse(p.x, p.y, 110, 55, Color::RGB(255, 255, 255)) - .unwrap(); + renderer.circle(p, 100, (255, 255, 255)); + renderer.circle(p, 110, (255, 255, 255)); + renderer.ellipse(p, (50, 100), (255, 255, 255)); + renderer.ellipse(p, (110, 55), (255, 255, 255)); } for b in &self.bolls { - b.draw(canvas, self.boll_size); + b.draw(renderer, self.boll_size); } } - fn leave(&self) { + fn leave(&mut self) { println!("number of bolls: {}", self.bolls.len()); } - fn on_event(&mut self, event: Event) { + fn handle_event(&mut self, event: Event) -> Option { match event { Event::KeyDown { keycode: Some(Keycode::KpPlus), @@ -441,5 +453,6 @@ impl AppState for ActiveState { ))), _ => {} } + None } }