2024-11-03 16:32:53 +00:00
|
|
|
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<EmulatorCommand>,
|
|
|
|
renderer: Option<GameRenderer>,
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2024-11-03 18:25:20 +00:00
|
|
|
let mut eye_contents = vec![0u8; 384 * 224 * 2];
|
2024-11-03 16:32:53 +00:00
|
|
|
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<EmulatorCommand>,
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|