2 use sdl2::event::Event;
3 use sdl2::{EventPump, VideoSubsystem};
4 use sdl2::keyboard::Keycode;
5 use sdl2::pixels::Color;
6 use sdl2::render::BlendMode;
7 use sdl2::render::Canvas;
8 use sdl2::video::{SwapInterval, Window};
10 use ::{SCREEN_HEIGHT, SCREEN_WIDTH};
12 use common::{Point2D, Rect};
13 use sprites::SpriteManager;
15 use point; // defined in common, but loaded from main...
17 pub type Nanoseconds = u64;
20 pub struct AppBuilder {
21 resolution: Rect<u16>,
22 state: Option<Box<dyn AppState>>,
23 title: Option<String>,
27 pub fn with_resolution(mut self, width: u16, height: u16) -> Self {
28 self.resolution = Rect { width, height };
32 pub fn with_state(mut self, state: Box<dyn AppState>) -> Self {
33 self.state = Some(state);
37 pub fn with_title(mut self, title: &str) -> Self {
38 self.title = Some(title.to_string());
42 pub fn build(self) -> Result<App, String> {
43 let context = sdl2::init().unwrap();
44 sdl2::image::init(sdl2::image::InitFlag::PNG)?;
45 let video = context.video()?;
47 self.print_video_display_modes(&video);
50 .window(&self.title.unwrap(), self.resolution.width.into(), self.resolution.height.into())
53 // .fullscreen_desktop()
56 context.mouse().show_cursor(false);
58 let mut canvas = window.into_canvas().build().unwrap();
59 canvas.set_blend_mode(BlendMode::Add);
60 canvas.set_draw_color(Color::RGB(0, 0, 0));
64 video.gl_set_swap_interval(SwapInterval::VSync)?;
66 let event_pump = context.event_pump()?;
67 let sprites = SpriteManager::new(canvas.texture_creator());
73 state: self.state.unwrap_or(Box::new(ActiveState::new())),
77 fn print_video_display_modes(&self, video: &VideoSubsystem) {
78 println!("video subsystem: {:?}", video);
79 println!("current_video_driver: {:?}", video.current_video_driver());
80 for display in 0..video.num_video_displays().unwrap() {
81 println!("=== display {} - {} ===", display, video.display_name(display).unwrap());
82 println!(" display_bounds: {:?}", video.display_bounds(display).unwrap());
83 println!(" num_display_modes: {:?}", video.num_display_modes(display).unwrap());
84 println!(" desktop_display_mode: {:?}", video.desktop_display_mode(display).unwrap());
85 println!(" current_display_mode: {:?}", video.current_display_mode(display).unwrap());
86 for mode in 0..video.num_display_modes(display).unwrap() {
87 println!(" {:2}: {:?}", mode, video.display_mode(display, mode).unwrap());
90 println!("swap interval: {:?}", video.gl_get_swap_interval());
95 pub canvas: Canvas<Window>,
96 pub event_pump: EventPump,
97 pub sprites: SpriteManager,
98 pub state: Box<dyn AppState>,
102 pub fn new() -> AppBuilder {
106 pub fn load_sprites(&mut self, sprites: &[(&str, &str)]) {
107 for (name, file) in sprites {
108 self.sprites.load(name, file);
114 fn update(&mut self, dt: Nanoseconds);
115 fn render(&self, canvas: &mut Canvas<Window>);
117 fn on_event(&mut self, event: Event);
120 type Bollar = Vec<Box<dyn Boll>>;
122 pub struct ActiveState {
128 pub fn new() -> ActiveState {
130 bolls: Bollar::new(),
135 fn change_boll_count(&mut self, delta: i32) {
140 } else if delta < 0 {
141 for _i in 0..(-delta) {
147 fn add_boll(&mut self) {
148 let mut rng = rand::thread_rng();
149 self.bolls.push(Box::new(SquareBoll {
150 pos: point!(rng.gen_range(0, SCREEN_WIDTH) as f64, rng.gen_range(0, SCREEN_HEIGHT) as f64),
151 vel: point!(rng.gen_range(-2.0, 2.0), rng.gen_range(-2.0, 2.0)),
156 impl AppState for ActiveState {
157 fn update(&mut self, dt: Nanoseconds) {
158 for b in &mut self.bolls {
163 ns if ns < (NS_PER_FRAME - 90_0000) as u64 => { self.change_boll_count(100) }
164 ns if ns > (NS_PER_FRAME + 90_0000) as u64 => { self.change_boll_count(-100) }
169 fn render(&self, canvas: &mut Canvas<Window>) {
170 for b in &self.bolls {
171 b.draw(canvas, self.boll_size);
176 println!("number of bolls: {}", self.bolls.len());
179 fn on_event(&mut self, event: Event) {
181 Event::KeyDown { keycode: Some(Keycode::KpPlus), .. } => { self.boll_size = std::cmp::min(self.boll_size + 1, 32) }
182 Event::KeyDown { keycode: Some(Keycode::KpMinus), .. } => { self.boll_size = std::cmp::max(self.boll_size - 1, 1) }
183 Event::MouseMotion { x, y, .. } => {
184 self.bolls.push(Box::new(CircleBoll::new(
185 point!(x as f64, y as f64),