moa/emulator/frontends/pixels/src/frontend.rs

182 lines
6.0 KiB
Rust

use instant::Instant;
use pixels::{Pixels, SurfaceTexture};
use winit::event::{Event, VirtualKeyCode, WindowEvent, ElementState};
use winit::event_loop::{ControlFlow, EventLoop};
use moa_core::{System, Error};
use moa_core::host::{Host, WindowUpdater, ControllerDevice, ControllerEvent, ControllerUpdater, Audio, DummyAudio};
use moa_core::host::gfx::Frame;
use moa_common::{AudioMixer, AudioSource, CpalAudioOutput};
use crate::settings;
use crate::create_window;
pub const WIDTH: u32 = 320;
pub const HEIGHT: u32 = 224;
pub type LoadSystemFn = fn (&mut PixelsFrontend, Vec<u8>) -> Result<System, Error>;
pub struct PixelsFrontend {
updater: Option<Box<dyn WindowUpdater>>,
controller: Option<Box<dyn ControllerUpdater>>,
//mixer: Arc<Mutex<AudioMixer>>,
//audio_output: CpalAudioOutput,
}
impl PixelsFrontend {
pub fn new() -> PixelsFrontend {
settings::get().run = true;
//let mixer = AudioMixer::with_default_rate();
//let audio_output = CpalAudioOutput::create_audio_output(mixer.lock().unwrap().get_sink());
PixelsFrontend {
controller: None,
updater: None,
//mixer,
//audio_output,
}
}
}
impl Host for PixelsFrontend {
fn add_window(&mut self, updater: Box<dyn WindowUpdater>) -> Result<(), Error> {
self.updater = Some(updater);
Ok(())
}
fn register_controller(&mut self, device: ControllerDevice, input: Box<dyn ControllerUpdater>) -> Result<(), Error> {
if device != ControllerDevice::A {
return Ok(())
}
self.controller = Some(input);
Ok(())
}
fn create_audio_source(&mut self) -> Result<Box<dyn Audio>, Error> {
//let source = AudioSource::new(self.mixer.clone());
//Ok(Box::new(source))
Ok(Box::new(DummyAudio()))
}
}
pub async fn run_loop(mut host: PixelsFrontend) {
let event_loop = EventLoop::new();
let window = create_window(&event_loop);
let mut pixels = {
let window_size = window.inner_size();
let surface_texture =
SurfaceTexture::new(window_size.width, window_size.height, window.as_ref());
Pixels::new_async(WIDTH, HEIGHT, surface_texture)
.await
.expect("Pixels error")
};
let mut last_size = (WIDTH, HEIGHT);
let mut last_frame = Frame::new(WIDTH, HEIGHT);
//let mut update_timer = Instant::now();
event_loop.run(move |event, _, control_flow| {
// Draw the current frame
if let Event::RedrawRequested(_) = event {
settings::increment_frames();
//log::warn!("updated after {:4}ms", update_timer.elapsed().as_millis());
//update_timer = Instant::now();
if let Some(updater) = host.updater.as_mut() {
if let Ok(frame) = updater.take_frame() {
last_frame = frame;
}
if (last_frame.width, last_frame.height) != last_size {
last_size = (last_frame.width, last_frame.height);
pixels.resize_buffer(last_frame.width, last_frame.height);
}
let buffer = pixels.get_frame();
buffer
.chunks_mut(4)
.zip(last_frame.bitmap.iter())
.for_each(|(dest, pixel)| {
dest[0] = (pixel >> 16) as u8;
dest[1] = (pixel >> 8) as u8;
dest[2] = *pixel as u8;
dest[3] = 255;
});
}
if pixels
.render()
.map_err(|e| log::error!("pixels.render() failed: {}", e))
.is_err()
{
*control_flow = ControlFlow::Exit;
return;
}
window.request_redraw();
}
// Process key inputs and pass them to the emulator's controller device
if let Event::WindowEvent { event: WindowEvent::KeyboardInput { input, .. }, .. } = event {
if let Some(keycode) = input.virtual_keycode {
let key = match input.state {
ElementState::Pressed => {
map_controller_a(keycode, true)
}
ElementState::Released => {
map_controller_a(keycode, false)
}
};
if let Some(updater) = host.controller.as_mut() {
if let Some(key) = key {
updater.update_controller(key);
}
}
}
}
// Check if the run flag is no longer true, and exit the loop
if !settings::get().run {
// Clear the screen
let buffer = pixels.get_frame();
buffer.iter_mut().for_each(|byte| *byte = 0);
if pixels
.render()
.map_err(|e| log::error!("pixels.render() failed: {}", e))
.is_err()
{
*control_flow = ControlFlow::Exit;
return;
}
window.request_redraw();
*control_flow = ControlFlow::Exit;
}
});
}
pub fn map_controller_a(key: VirtualKeyCode, state: bool) -> Option<ControllerEvent> {
match key {
VirtualKeyCode::A => { Some(ControllerEvent::ButtonA(state)) },
VirtualKeyCode::S => { Some(ControllerEvent::ButtonB(state)) },
VirtualKeyCode::D => { Some(ControllerEvent::ButtonC(state)) },
VirtualKeyCode::Up => { Some(ControllerEvent::DpadUp(state)) },
VirtualKeyCode::Down => { Some(ControllerEvent::DpadDown(state)) },
VirtualKeyCode::Left => { Some(ControllerEvent::DpadLeft(state)) },
VirtualKeyCode::Right => { Some(ControllerEvent::DpadRight(state)) },
VirtualKeyCode::Return => { Some(ControllerEvent::Start(state)) },
VirtualKeyCode::M => { Some(ControllerEvent::Mode(state)) },
_ => None,
}
}