shrooms-vb-native/src/emulator.rs

131 lines
3.3 KiB
Rust
Raw Normal View History

2024-11-03 16:32:53 +00:00
use std::{
fs,
2024-11-04 14:59:58 +00:00
path::{Path, PathBuf},
2024-11-03 16:32:53 +00:00
sync::mpsc::{self, TryRecvError},
};
use anyhow::Result;
2024-11-04 14:59:58 +00:00
use crate::{audio::Audio, renderer::GameRenderer, shrooms_vb_core::CoreVB};
pub struct EmulatorBuilder {
rom: Option<PathBuf>,
commands: mpsc::Receiver<EmulatorCommand>,
}
impl EmulatorBuilder {
pub fn new() -> (Self, EmulatorClient) {
let (queue, commands) = mpsc::channel();
let builder = Self {
rom: None,
commands,
};
let client = EmulatorClient { queue };
(builder, client)
}
pub fn with_rom(self, path: &Path) -> Self {
Self {
rom: Some(path.into()),
..self
}
}
pub fn build(self) -> Result<Emulator> {
let mut emulator = Emulator::new(self.commands)?;
if let Some(path) = self.rom {
emulator.load_rom(&path)?;
}
Ok(emulator)
}
}
2024-11-03 16:32:53 +00:00
pub struct Emulator {
sim: CoreVB,
2024-11-04 14:59:58 +00:00
audio: Audio,
2024-11-03 16:32:53 +00:00
commands: mpsc::Receiver<EmulatorCommand>,
renderer: Option<GameRenderer>,
}
impl Emulator {
2024-11-04 14:59:58 +00:00
fn new(commands: mpsc::Receiver<EmulatorCommand>) -> Result<Self> {
Ok(Self {
2024-11-03 16:32:53 +00:00
sim: CoreVB::new(),
2024-11-04 14:59:58 +00:00
audio: Audio::init()?,
commands,
2024-11-03 16:32:53 +00:00
renderer: None,
2024-11-04 14:59:58 +00:00
})
2024-11-03 16:32:53 +00:00
}
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];
2024-11-04 14:59:58 +00:00
let mut audio_samples = vec![];
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);
}
}
2024-11-04 14:59:58 +00:00
self.sim.read_samples(&mut audio_samples);
if !audio_samples.is_empty() {
self.audio.update(&audio_samples);
audio_samples.clear();
}
2024-11-03 16:32:53 +00:00
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
);
}
}
}