Moved main loop to App
[kaka/rust-sdl-test.git] / src / game / app.rs
index 362af2e..4e0f97b 100644 (file)
@@ -1,21 +1,28 @@
+use boll::*;
+use common::{Point2D, Rect};
+use point; // defined in common, but loaded from main...
 use rand::Rng;
 use sdl2::event::Event;
-use sdl2::{EventPump, VideoSubsystem};
+use sdl2::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;
 use sdl2::render::Canvas;
+use sdl2::video::FullscreenType;
 use sdl2::video::{SwapInterval, Window};
-
-use ::{SCREEN_HEIGHT, SCREEN_WIDTH};
-use boll::*;
-use common::{Point2D, Rect};
+use sdl2::{EventPump, VideoSubsystem};
 use sprites::SpriteManager;
-use NS_PER_FRAME;
-use point; // defined in common, but loaded from main...
+use std::f32::consts::PI;
+use time::PreciseTime;
+use {SCREEN_HEIGHT, SCREEN_WIDTH};
 
 pub type Nanoseconds = u64;
 
+const FPS: u32 = 60;
+const NS_PER_FRAME: u32 = 1_000_000_000 / FPS;
+
 #[derive(Default)]
 pub struct AppBuilder {
     resolution: Rect<u16>,
@@ -25,34 +32,39 @@ pub struct AppBuilder {
 
 impl AppBuilder {
     pub fn with_resolution(mut self, width: u16, height: u16) -> Self {
-       self.resolution = Rect { width, height };
-       self
+        self.resolution = Rect { width, height };
+        self
     }
 
     pub fn with_state(mut self, state: Box<dyn AppState>) -> Self {
-       self.state = Some(state);
-       self
+        self.state = Some(state);
+        self
     }
 
     pub fn with_title(mut self, title: &str) -> Self {
-       self.title = Some(title.to_string());
-       self
+        self.title = Some(title.to_string());
+        self
     }
 
     pub fn build(self) -> Result<App, String> {
         let context = sdl2::init().unwrap();
         sdl2::image::init(sdl2::image::InitFlag::PNG)?;
-       let video = context.video()?;
+        let video = context.video()?;
 
-       self.print_video_display_modes(&video);
+        self.print_video_display_modes(&video);
 
         let window = video
-           .window(&self.title.unwrap(), self.resolution.width.into(), self.resolution.height.into())
+            .window(
+                &self.title.unwrap(),
+                self.resolution.width.into(),
+                self.resolution.height.into(),
+            )
             .position_centered()
-       // .fullscreen()
-       // .fullscreen_desktop()
+            // .fullscreen()
+            // .fullscreen_desktop()
             .opengl()
-            .build().unwrap();
+            .build()
+            .unwrap();
         context.mouse().show_cursor(false);
 
         let mut canvas = window.into_canvas().build().unwrap();
@@ -61,7 +73,7 @@ impl AppBuilder {
         canvas.clear();
         canvas.present();
 
-       video.gl_set_swap_interval(SwapInterval::VSync)?;
+        video.gl_set_swap_interval(SwapInterval::VSync)?;
 
         let event_pump = context.event_pump()?;
         let sprites = SpriteManager::new(canvas.texture_creator());
@@ -75,19 +87,39 @@ impl AppBuilder {
     }
 
     fn print_video_display_modes(&self, video: &VideoSubsystem) {
-       println!("video subsystem: {:?}", video);
-       println!("current_video_driver: {:?}", video.current_video_driver());
-       for display in 0..video.num_video_displays().unwrap() {
-           println!("=== display {} - {} ===", display, video.display_name(display).unwrap());
-           println!(" display_bounds: {:?}", video.display_bounds(display).unwrap());
-           println!(" num_display_modes: {:?}", video.num_display_modes(display).unwrap());
-           println!(" desktop_display_mode: {:?}", video.desktop_display_mode(display).unwrap());
-           println!(" current_display_mode: {:?}", video.current_display_mode(display).unwrap());
-           for mode in 0..video.num_display_modes(display).unwrap() {
-               println!("  {:2}: {:?}", mode, video.display_mode(display, mode).unwrap());
-           }
-       }
-       println!("swap interval: {:?}", video.gl_get_swap_interval());
+        println!("video subsystem: {:?}", video);
+        println!("current_video_driver: {:?}", video.current_video_driver());
+        for display in 0..video.num_video_displays().unwrap() {
+            println!(
+                "=== display {} - {} ===",
+                display,
+                video.display_name(display).unwrap()
+            );
+            println!(
+                " display_bounds: {:?}",
+                video.display_bounds(display).unwrap()
+            );
+            println!(
+                " num_display_modes: {:?}",
+                video.num_display_modes(display).unwrap()
+            );
+            println!(
+                " desktop_display_mode: {:?}",
+                video.desktop_display_mode(display).unwrap()
+            );
+            println!(
+                " current_display_mode: {:?}",
+                video.current_display_mode(display).unwrap()
+            );
+            for mode in 0..video.num_display_modes(display).unwrap() {
+                println!(
+                    "  {:2}: {:?}",
+                    mode,
+                    video.display_mode(display, mode).unwrap()
+                );
+            }
+        }
+        println!("swap interval: {:?}", video.gl_get_swap_interval());
     }
 }
 
@@ -100,7 +132,7 @@ pub struct App {
 
 impl App {
     pub fn new() -> AppBuilder {
-       Default::default()
+        Default::default()
     }
 
     pub fn load_sprites(&mut self, sprites: &[(&str, &str)]) {
@@ -108,6 +140,205 @@ impl App {
             self.sprites.load(name, file);
         }
     }
+
+    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 mario_angle = 0.0;
+
+        'running: loop {
+            self.canvas.set_draw_color(Color::RGB(0, 0, 0));
+            self.canvas.clear();
+            {
+                let blocks = 20;
+                let size = 32;
+                let offset = point!(
+                    (SCREEN_WIDTH as i32 - (blocks + 1) * size) / 2,
+                    (SCREEN_HEIGHT as i32 - (blocks + 1) * size) / 2
+                );
+                let block = self.sprites.get("block");
+                for i in 0..blocks {
+                    self.canvas
+                        .copy(
+                            block,
+                            None,
+                            SDLRect::new((i) * size + offset.x, offset.y, size as u32, size as u32),
+                        )
+                        .unwrap();
+                    self.canvas
+                        .copy(
+                            block,
+                            None,
+                            SDLRect::new(
+                                (blocks - i) * size + offset.x,
+                                (blocks) * size + offset.y,
+                                size as u32,
+                                size as u32,
+                            ),
+                        )
+                        .unwrap();
+                    self.canvas
+                        .copy(
+                            block,
+                            None,
+                            SDLRect::new(
+                                offset.x,
+                                (blocks - i) * size + offset.y,
+                                size as u32,
+                                size as u32,
+                            ),
+                        )
+                        .unwrap();
+                    self.canvas
+                        .copy(
+                            block,
+                            None,
+                            SDLRect::new(
+                                (blocks) * size + offset.x,
+                                (i) * size + offset.y,
+                                size as u32,
+                                size as u32,
+                            ),
+                        )
+                        .unwrap();
+                }
+            }
+            {
+                let size = 64;
+                let offset = point!(
+                    (SCREEN_WIDTH as i32 - size) / 2,
+                    (SCREEN_HEIGHT as i32 - size) / 2
+                );
+                let radius = 110.0 + size as f32 * 0.5;
+                let angle = (mario_angle as f32 - 90.0) * PI / 180.0;
+                let offset2 = point!((angle.cos() * radius) as i32, (angle.sin() * radius) as i32);
+                self.canvas
+                    .copy_ex(
+                        self.sprites.get("mario"),
+                        None,
+                        SDLRect::new(
+                            offset.x + offset2.x,
+                            offset.y + offset2.y,
+                            size as u32,
+                            size as u32,
+                        ),
+                        mario_angle,
+                        sdl2::rect::Point::new(size / 2, size / 2),
+                        false,
+                        false,
+                    )
+                    .unwrap();
+                mario_angle += 1.0;
+                if mario_angle >= 360.0 {
+                    mario_angle -= 360.0
+                }
+            }
+            {
+                let p = point!((SCREEN_WIDTH / 2) as i16, (SCREEN_HEIGHT / 2) as i16);
+                self.canvas
+                    .circle(p.x, p.y, 100, Color::RGB(255, 255, 255))
+                    .unwrap();
+                self.canvas
+                    .aa_circle(p.x, p.y, 110, Color::RGB(255, 255, 255))
+                    .unwrap();
+                self.canvas
+                    .ellipse(p.x, p.y, 50, 100, Color::RGB(255, 255, 255))
+                    .unwrap();
+                self.canvas
+                    .aa_ellipse(p.x, p.y, 110, 55, Color::RGB(255, 255, 255))
+                    .unwrap();
+            }
+
+            //        window.gl_swap_window();
+            for event in self.event_pump.poll_iter() {
+                match event {
+                    Event::Quit { .. }
+                    | Event::KeyDown {
+                        keycode: Some(Keycode::Escape),
+                        ..
+                    } => {
+                        break 'running;
+                    }
+                    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();
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::Resized(x, y),
+                        ..
+                    } => {
+                        println!("window resized({}, {})", x, y)
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::Maximized,
+                        ..
+                    } => {
+                        println!("window maximized")
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::Restored,
+                        ..
+                    } => {
+                        println!("window restored")
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::Enter,
+                        ..
+                    } => {
+                        println!("window enter")
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::Leave,
+                        ..
+                    } => {
+                        println!("window leave")
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::FocusGained,
+                        ..
+                    } => {
+                        println!("window focus gained")
+                    }
+                    Event::Window {
+                        win_event: WindowEvent::FocusLost,
+                        ..
+                    } => {
+                        println!("window focus lost")
+                    }
+                    _ => self.state.on_event(event),
+                }
+            }
+
+            let duration =
+                last_time.to(PreciseTime::now()).num_nanoseconds().unwrap() as Nanoseconds;
+            last_time = PreciseTime::now();
+            self.state.update(duration);
+            self.state.render(&mut self.canvas);
+            self.canvas.present();
+
+            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();
+            }
+        }
+
+        self.state.leave();
+    }
 }
 
 pub trait AppState {
@@ -147,7 +378,10 @@ impl ActiveState {
     fn add_boll(&mut self) {
         let mut rng = rand::thread_rng();
         self.bolls.push(Box::new(SquareBoll {
-            pos: point!(rng.gen_range(0, SCREEN_WIDTH) as f64, rng.gen_range(0, SCREEN_HEIGHT) as f64),
+            pos: point!(
+                rng.gen_range(0, SCREEN_WIDTH) as f64,
+                rng.gen_range(0, SCREEN_HEIGHT) as f64
+            ),
             vel: point!(rng.gen_range(-2.0, 2.0), rng.gen_range(-2.0, 2.0)),
         }));
     }
@@ -160,8 +394,8 @@ impl AppState for ActiveState {
         }
 
         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) as u64 => self.change_boll_count(100),
+            ns if ns > (NS_PER_FRAME + 90_0000) as u64 => self.change_boll_count(-100),
             _ => {}
         }
     }
@@ -178,14 +412,18 @@ impl AppState for ActiveState {
 
     fn on_event(&mut self, event: Event) {
         match event {
-            Event::KeyDown { keycode: Some(Keycode::KpPlus), .. } => { self.boll_size = std::cmp::min(self.boll_size + 1, 32) }
-            Event::KeyDown { keycode: Some(Keycode::KpMinus), .. } => { self.boll_size = std::cmp::max(self.boll_size - 1, 1) }
-            Event::MouseMotion { x, y, .. } => {
-                self.bolls.push(Box::new(CircleBoll::new(
-                    point!(x as f64, y as f64),
-                    point!(0.0, 0.0),
-                )))
-            }
+            Event::KeyDown {
+                keycode: Some(Keycode::KpPlus),
+                ..
+            } => self.boll_size = std::cmp::min(self.boll_size + 1, 32),
+            Event::KeyDown {
+                keycode: Some(Keycode::KpMinus),
+                ..
+            } => self.boll_size = std::cmp::max(self.boll_size - 1, 1),
+            Event::MouseMotion { x, y, .. } => self.bolls.push(Box::new(CircleBoll::new(
+                point!(x as f64, y as f64),
+                point!(0.0, 0.0),
+            ))),
             _ => {}
         }
     }