device.rs
1 use crate::display::Display; 2 use crate::rom::Ch8Rom; 3 use crate::vm::VM; 4 use anyhow::Result; 5 use sdl2::event::Event; 6 use sdl2::keyboard::Keycode; 7 use sdl2::pixels::Color; 8 use sdl2::video::Window; 9 use sdl2::{rect::Rect, render::Canvas}; 10 11 pub struct Device { 12 pub vm: VM, 13 } 14 15 impl Device { 16 pub fn new(rom: Ch8Rom) -> Result<Self> { 17 Ok(Device { vm: VM::new(rom)? }) 18 } 19 20 pub fn initialize(&mut self) -> Result<()> { 21 self.vm.initialize()?; 22 23 Ok(()) 24 } 25 26 pub fn run(&mut self) -> Result<()> { 27 // SDL2 Setup 28 let sdl_context = sdl2::init().map_err(anyhow::Error::msg)?; 29 let video_subsys = sdl_context.video().map_err(anyhow::Error::msg)?; 30 let window = video_subsys 31 .window("Chip8 Emulator", Display::WIDTH * Display::SCALE, Display::HEIGHT * Display::SCALE) 32 .position_centered() 33 .opengl() 34 .build()?; 35 36 let mut canvas = window.into_canvas().present_vsync().build()?; 37 38 canvas.clear(); 39 canvas.present(); 40 41 let mut event_pump = sdl_context.event_pump().map_err(anyhow::Error::msg)?; 42 'vmevloop: loop { 43 for evt in event_pump.poll_iter() { 44 match evt { 45 Event::Quit { .. } 46 | Event::KeyDown { 47 keycode: Some(Keycode::Escape), 48 .. 49 } => break 'vmevloop, 50 Event::KeyDown { 51 keycode: Some(key), .. 52 } => match key { 53 Keycode::Num1 => self.vm.keyboard[0] = true, 54 Keycode::Num2 => self.vm.keyboard[1] = true, 55 Keycode::Num3 => self.vm.keyboard[2] = true, 56 Keycode::Num4 => self.vm.keyboard[3] = true, 57 Keycode::Q => self.vm.keyboard[4] = true, 58 Keycode::W => self.vm.keyboard[5] = true, 59 Keycode::E => self.vm.keyboard[6] = true, 60 Keycode::R => self.vm.keyboard[7] = true, 61 Keycode::A => self.vm.keyboard[8] = true, 62 Keycode::S => self.vm.keyboard[9] = true, 63 Keycode::D => self.vm.keyboard[10] = true, 64 Keycode::F => self.vm.keyboard[11] = true, 65 Keycode::Z => self.vm.keyboard[12] = true, 66 Keycode::X => self.vm.keyboard[13] = true, 67 Keycode::C => self.vm.keyboard[14] = true, 68 Keycode::V => self.vm.keyboard[15] = true, 69 _ => (), 70 }, 71 Event::KeyUp { 72 keycode: Some(key), .. 73 } => match key { 74 Keycode::Num1 => self.vm.keyboard[0] = false, 75 Keycode::Num2 => self.vm.keyboard[1] = false, 76 Keycode::Num3 => self.vm.keyboard[2] = false, 77 Keycode::Num4 => self.vm.keyboard[3] = false, 78 Keycode::Q => self.vm.keyboard[4] = false, 79 Keycode::W => self.vm.keyboard[5] = false, 80 Keycode::E => self.vm.keyboard[6] = false, 81 Keycode::R => self.vm.keyboard[7] = false, 82 Keycode::A => self.vm.keyboard[8] = false, 83 Keycode::S => self.vm.keyboard[9] = false, 84 Keycode::D => self.vm.keyboard[10] = false, 85 Keycode::F => self.vm.keyboard[11] = false, 86 Keycode::Z => self.vm.keyboard[12] = false, 87 Keycode::X => self.vm.keyboard[13] = false, 88 Keycode::C => self.vm.keyboard[14] = false, 89 Keycode::V => self.vm.keyboard[15] = false, 90 _ => (), 91 }, 92 _ => (), 93 } 94 } 95 96 for _ in 0..Display::TICKS_PER_FRAME { 97 self.vm.tick()?; 98 } 99 100 self.draw_screen(&mut canvas)?; 101 } 102 103 Ok(()) 104 } 105 106 107 fn draw_screen(&self, canvas: &mut Canvas<Window>) -> Result<()> { 108 for (y, row) in self.vm.vram.iter().enumerate() { 109 for (x, &col) in row.iter().enumerate() { 110 let x = (x as u32) * Display::SCALE; 111 let y = (y as u32) * Display::SCALE; 112 if col == 0 { 113 canvas.set_draw_color(Color::RGB(0, 0, 0)); 114 } else { 115 canvas.set_draw_color(Color::RGB(255, 255, 255)); 116 } 117 118 let _ = canvas 119 .fill_rect(Rect::new(x as i32, y as i32, Display::SCALE, Display::SCALE)); 120 } 121 } 122 canvas.present(); 123 124 Ok(()) 125 } 126 }