use std::{ fs, path::Path, sync::mpsc::{self, TryRecvError}, }; use anyhow::Result; use crate::{renderer::GameRenderer, shrooms_vb_core::CoreVB}; pub struct Emulator { sim: CoreVB, commands: mpsc::Receiver, renderer: Option, } impl Emulator { pub fn new() -> (Self, EmulatorClient) { let (sink, source) = mpsc::channel(); let emu = Emulator { sim: CoreVB::new(), commands: source, renderer: None, }; let queue = EmulatorClient { queue: sink }; (emu, queue) } pub fn load_rom(&mut self, path: &Path) -> Result<()> { let bytes = fs::read(path)?; self.sim.load_rom(bytes)?; Ok(()) } pub fn run(&mut self) { let mut eye_contents = vec![0u8; 384 * 224 * 2]; loop { self.sim.emulate_frame(); if let Some(renderer) = &mut self.renderer { if self.sim.read_pixels(&mut eye_contents) { renderer.render(&eye_contents); } } loop { match self.commands.try_recv() { Ok(command) => self.handle_command(command), Err(TryRecvError::Empty) => { break; } Err(TryRecvError::Disconnected) => { return; } } } } } fn handle_command(&mut self, command: EmulatorCommand) { match command { EmulatorCommand::SetRenderer(renderer) => { self.renderer = Some(renderer); } EmulatorCommand::PressStart => { self.sim.set_keys(0x1003); } EmulatorCommand::ReleaseStart => { self.sim.set_keys(0x0003); } } } } #[derive(Debug)] pub enum EmulatorCommand { SetRenderer(GameRenderer), PressStart, ReleaseStart, } pub struct EmulatorClient { queue: mpsc::Sender, } impl EmulatorClient { pub fn send_command(&self, command: EmulatorCommand) { if let Err(err) = self.queue.send(command) { eprintln!( "could not send command {:?} as emulator is shut down", err.0 ); } } }