1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use log::error;
use pixels::{Error, Pixels, SurfaceTexture};
use winit::dpi::LogicalSize;
use winit::event::{Event, VirtualKeyCode};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
use winit_input_helper::WinitInputHelper;
// use std::time::Duration;

/// Stores state for a black and white window
pub struct StateBW {
    pub active: Vec<bool>,//[bool; width as usize*HEIGHT as usize],
    width: u32,
    height: u32,
}
impl StateBW {
    fn new(width: u32, height: u32) -> StateBW {
        StateBW{ active: vec![true; width as usize*height as usize], width: width, height: height}
    }
    /// Draws all pixels stored in `active` to the screen
    fn draw(&self, frame: &mut [u8]) {
        for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
            let rgba = if self.active[i] {
                [0xFF, 0xFF, 0xFF, 0xFF]
            } else {
                [0x00, 0x00, 0x00, 0x00]
            };
            pixel.copy_from_slice(&rgba);
        }
    }
    /// Returns the value at the given position
    pub fn get(&self, x: u32, y: u32) -> bool {
        self.active[ (y*self.width + x) as usize ]
    }
    /// Sets the value at the given position to the new value
    pub fn set(&mut self, x: u32, y: u32, new: bool) {
        self.active[ (y*self.width + x) as usize ] = new;
    }
    /// Flips the bit at the given position
    pub fn switch(&mut self, x: u32, y: u32) {
        self.active[ (y*self.width + x) as usize ] = !self.get(x, y);
    }
}

pub struct WinBW {
    width: u32,
    height: u32,
}

impl WinBW {
    pub fn new(width: u32, height: u32) -> WinBW {
        WinBW{width: width, height: height}
    }
    /// Runs the main loop
    /// # Arguments
    /// * `looper` - A reference to the function called at each loop
    /// * `state_manager - The struct instance that holds state data
    /// * `fps` - The FPS cap for the window
    pub fn run<T>(&mut self, looper: &'static (dyn for<'r, 's> Fn(&'r mut StateBW, &'s mut T) + 'static), mut state_manager: T , fps: u64) -> Result<(), Error>  {
        env_logger::init();
        let event_loop = EventLoop::new();
        let mut input = WinitInputHelper::new();
        let window = {
            let size = LogicalSize::new(self.width as f64, self.height as f64);
            WindowBuilder::new()
                .with_title("Emulator")
                .with_inner_size(size)
                .with_min_inner_size(size)
                .build(&event_loop)
                .unwrap()
        };

        let mut pixels = {
            let window_size = window.inner_size();
            let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
            Pixels::new(self.width, self.height, surface_texture)?
        };

        let mut world = StateBW::new(self.width, self.height);

        // let sleeper = Duration::from_secs(1/fps);

        event_loop.run(move |event, _, control_flow| {

            // thread::sleep(sleeper);

            // Draw current frame
            if let Event::RedrawRequested(_) = event {
                world.draw(pixels.get_frame());
                if pixels
                    .render()
                    .map_err(|e| error!("pixels.render() failed: {}", e))
                    .is_err()
                {
                    *control_flow = ControlFlow::Exit;
                    return;
                }
            }

            // Handle input events
            if input.update(&event) {

                if input.key_pressed(VirtualKeyCode::Escape) || input.quit() {
                    *control_flow = ControlFlow::Exit;
                    return;
                }

                if let Some(size) = input.window_resized() {
                    pixels.resize_surface(size.width, size.height);
                }

                looper(&mut world, &mut state_manager);
                window.request_redraw();

            }

        });
    }
}