use std::marker::PhantomData; use std::sync::{Arc, Mutex}; pub use crate::processor::memory::mmio::gpu::Colour; pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState}; pub use crate::processor::memory::mmio::serial::SerialTarget; pub use crate::processor::CpuSaveState; pub use crate::{HEIGHT, WIDTH}; use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb}; pub enum EmulatorMessage { Stop, } #[derive(Clone, Copy)] pub enum DownsampleType { Linear, ZeroOrderHold, } pub enum RomFile { Path(String), Raw(Vec), } pub trait Renderer> { fn prepare(&mut self, width: usize, height: usize); fn resize(&mut self, width: usize, height: usize) { self.prepare(width, height) } fn display(&mut self, buffer: &[Format]); fn set_title(&mut self, _title: String) {} fn latest_joypad_state(&mut self) -> JoypadState; fn set_rumble(&mut self, _rumbling: bool) {} } pub struct AudioOutput { pub sample_rate: f32, pub send_rb: AsyncHeapProducer<[f32; 2]>, pub downsample_type: DownsampleType, } impl AudioOutput { pub fn new( sample_rate: f32, buffers_per_frame: usize, downsample_type: DownsampleType, ) -> (Self, AsyncHeapConsumer<[f32; 2]>) { let rb_len = (sample_rate as usize / 60) / buffers_per_frame; let rb = AsyncHeapRb::<[f32; 2]>::new(rb_len); let (send_rb, rx) = rb.split(); ( Self { sample_rate, send_rb, downsample_type, }, rx, ) } } pub trait PocketCamera { // resolution - 128x128 fn get_image(&mut self) -> [u8; 128 * 128]; fn begin_capture(&mut self); fn init(&mut self); } pub struct NoCamera { buf: [u8; 128 * 128], } impl Default for NoCamera { fn default() -> Self { Self { buf: [0; 128 * 128], } } } impl PocketCamera for NoCamera { fn get_image(&mut self) -> [u8; 128 * 128] { self.buf } fn begin_capture(&mut self) { for v in &mut self.buf { *v = rand::random(); } } fn init(&mut self) {} } pub(crate) type CameraWrapperRef = Arc>>; pub(crate) struct CameraWrapper where C: PocketCamera, { pub(crate) inner: C, counter: usize, next_image: Option<[u8; 128 * 128]>, } impl CameraWrapper where C: PocketCamera, { pub(crate) fn new(camera: C) -> Self { Self { inner: camera, counter: 0, next_image: None, } } pub(crate) fn is_capturing(&self) -> bool { self.counter > 0 } pub(crate) fn tick(&mut self, steps: usize) { if self.counter > 0 { self.counter = match self.counter.checked_sub(steps) { Some(num) => num, None => { self.next_image = Some(self.inner.get_image()); 0 } }; } } pub(crate) fn begin_capture(&mut self) { self.counter = 32446 * 4; self.inner.begin_capture(); } pub(crate) fn get_next(&mut self) -> Option<[u8; 128 * 128]> { self.next_image.take() } } #[non_exhaustive] pub struct EmulatorOptions where ColourFormat: From + Clone, R: Renderer, { pub(crate) window: R, pub(crate) tile_window: Option, pub(crate) rom: RomFile, pub(crate) output: AudioOutput, pub(crate) save_path: Option, pub(crate) no_save: bool, pub(crate) bootrom: Option, pub(crate) show_bootrom: bool, pub(crate) serial_target: SerialTarget, pub(crate) cgb_mode: bool, spooky: PhantomData, } impl EmulatorOptions where ColourFormat: From + Clone, R: Renderer, { pub fn new(window: R, rom: RomFile, output: AudioOutput) -> Self { Self { window, tile_window: None, rom, output, save_path: None, no_save: false, bootrom: None, show_bootrom: false, serial_target: SerialTarget::None, cgb_mode: true, spooky: PhantomData, } } pub fn with_save_path(mut self, path: Option) -> Self { self.save_path = path; self } pub fn force_no_save(mut self) -> Self { self.no_save = true; self } pub fn with_no_save(mut self, no_save: bool) -> Self { self.no_save = no_save; self } pub fn with_bootrom(mut self, bootrom: Option, show_bootrom: bool) -> Self { self.bootrom = bootrom; self.show_bootrom = show_bootrom; self } pub fn with_stdout(mut self) -> Self { self.serial_target = SerialTarget::Stdout; self } pub fn with_serial_target(mut self, target: SerialTarget) -> Self { self.serial_target = target; self } pub fn with_tile_window(mut self, window: Option) -> Self { self.tile_window = window; self } pub fn with_cgb_mode(mut self, cgb_mode: bool) -> Self { self.cgb_mode = cgb_mode; self } } pub trait EmulatorCoreTrait { fn replace_output(&mut self, new: AudioOutput); fn cycle_count(&self) -> usize; fn pc(&self) -> u16; fn print_reg(&self) -> String; fn get_memory(&self, address: u16) -> u8; fn run(&mut self); fn run_stepped(&mut self, step_size: usize); fn run_until_buffer_full(&mut self); }