fix windows

This commit is contained in:
Alex Janka 2023-05-03 14:15:59 +10:00
parent 9e836927c4
commit 429e3b4085
2 changed files with 234 additions and 150 deletions

View file

@ -11,8 +11,11 @@ use gb_emu_lib::{
EmulatorCore, EmulatorCore,
}; };
use gilrs::Gilrs; use gilrs::Gilrs;
use std::sync::mpsc::channel; use std::{
use window::WindowRenderer; sync::mpsc::channel,
time::{Duration, Instant},
};
use window::{WindowManager, WindowRenderer};
mod audio; mod audio;
#[cfg(feature = "camera")] #[cfg(feature = "camera")]
@ -75,18 +78,28 @@ struct Args {
fn main() { fn main() {
let args = Args::parse(); let args = Args::parse();
EmulatorHandler::run(args);
}
enum EmulatorTypes {
Debug(Debugger),
Normal(Box<dyn EmulatorCoreTrait>),
}
struct EmulatorHandler {
emu: EmulatorTypes,
window_manager: WindowManager,
since: Instant,
}
impl EmulatorHandler {
fn run(args: Args) -> ! {
let factor = if let Some(factor) = args.scale_factor { let factor = if let Some(factor) = args.scale_factor {
factor factor
} else { } else {
3 3
}; };
let tile_window: Option<WindowRenderer> = if args.tile_window {
Some(WindowRenderer::new(factor, None))
} else {
None
};
let (sender, receiver) = channel::<EmulatorMessage>(); let (sender, receiver) = channel::<EmulatorMessage>();
let (debug_sender, debug_receiver) = channel::<EmulatorMessage>(); let (debug_sender, debug_receiver) = channel::<EmulatorMessage>();
@ -97,10 +110,17 @@ fn main() {
.unwrap(); .unwrap();
let (output, _stream) = audio::create_output(args.mute); let (output, _stream) = audio::create_output(args.mute);
let window = WindowRenderer::new(factor, Some(Gilrs::new().unwrap()));
let rom = RomFile::Path(args.rom); let rom = RomFile::Path(args.rom);
let mut window_manager = WindowManager::new();
let window = window_manager.add(factor, Some(Gilrs::new().unwrap()));
let tile_window: Option<WindowRenderer> = if args.tile_window {
Some(window_manager.add(factor, None))
} else {
None
};
let options = EmulatorOptions::new(window, rom, output) let options = EmulatorOptions::new(window, rom, output)
.with_save_path(args.save) .with_save_path(args.save)
.with_serial_target(if args.connect_serial { .with_serial_target(if args.connect_serial {
@ -125,27 +145,32 @@ fn main() {
#[cfg(feature = "camera")] #[cfg(feature = "camera")]
let core = Box::new(EmulatorCore::init(receiver, options, Webcam::new())); let core = Box::new(EmulatorCore::init(receiver, options, Webcam::new()));
let mut handler = if args.debug { let emu = if args.debug {
EmulatorHandler::Debug(Debugger::new(core, debug_receiver)) EmulatorTypes::Debug(Debugger::new(core, debug_receiver))
} else { } else {
EmulatorHandler::Normal(core) EmulatorTypes::Normal(core)
}; };
let since = Instant::now();
let mut h = Self {
emu,
window_manager,
since,
};
loop { loop {
handler.run(); h.cycle();
} }
} }
enum EmulatorHandler { fn cycle(&mut self) {
Debug(Debugger), if self.since.elapsed() >= Duration::from_millis(10) {
Normal(Box<dyn EmulatorCoreTrait>), self.window_manager.update_events();
self.since = Instant::now();
} }
match self.emu {
impl EmulatorHandler { EmulatorTypes::Debug(ref mut debugger) => debugger.step(),
fn run(&mut self) { EmulatorTypes::Normal(ref mut core) => core.run(),
match self {
EmulatorHandler::Debug(ref mut debugger) => debugger.step(),
EmulatorHandler::Normal(ref mut core) => core.run(),
} }
} }
} }

View file

@ -1,3 +1,8 @@
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use gb_emu_lib::{ use gb_emu_lib::{
connect::{JoypadState, Renderer}, connect::{JoypadState, Renderer},
util::scale_buffer_in_place, util::scale_buffer_in_place,
@ -12,16 +17,86 @@ use winit::{
event::{Event, VirtualKeyCode, WindowEvent}, event::{Event, VirtualKeyCode, WindowEvent},
event_loop::EventLoop, event_loop::EventLoop,
platform::run_return::EventLoopExtRunReturn, platform::run_return::EventLoopExtRunReturn,
window::{Window, WindowBuilder}, window::{Window, WindowBuilder, WindowId},
}; };
use winit_input_helper::WinitInputHelper; use winit_input_helper::WinitInputHelper;
pub struct WindowRenderer { pub struct WindowInfo {
event_loop: EventLoop<()>, id: WindowId,
window: Window, data: Arc<Mutex<WindowData>>,
input: WinitInputHelper, }
pixels: Pixels,
pub struct WindowData {
scaled_buf: Vec<[u8; 4]>, scaled_buf: Vec<[u8; 4]>,
pixels: Pixels,
}
pub struct WindowManager {
event_loop: EventLoop<()>,
windows: HashMap<WindowId, Arc<Mutex<WindowData>>>,
input: Arc<Mutex<WinitInputHelper>>,
}
impl WindowManager {
pub(crate) fn new() -> Self {
Self {
event_loop: EventLoop::new(),
windows: HashMap::new(),
input: Arc::new(Mutex::new(WinitInputHelper::new())),
}
}
pub(crate) fn add(&mut self, factor: usize, gamepad_handler: Option<Gilrs>) -> WindowRenderer {
let (r, info) = WindowRenderer::new(
factor,
gamepad_handler,
self.input.clone(),
&self.event_loop,
);
self.windows.insert(info.id, info.data);
r
}
pub fn update_events(&mut self) {
self.event_loop.run_return(|event, _, control_flow| {
control_flow.set_wait();
if let Ok(mut i) = self.input.lock() {
i.update(&event);
}
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id: _,
} => {
// quit = true;
}
Event::MainEventsCleared => {
control_flow.set_exit();
}
Event::RedrawRequested(window_id) => {
if let Some(w) = self.windows.get(&window_id) {
if let Ok(mut w) = w.lock() {
let scaled = w.scaled_buf.clone();
for (pixel, source) in
w.pixels.frame_mut().chunks_exact_mut(4).zip(&scaled)
{
pixel.copy_from_slice(source);
}
w.pixels.render().unwrap();
}
}
}
_ => {}
}
});
}
}
pub struct WindowRenderer {
window: Window,
input: Arc<Mutex<WinitInputHelper>>,
data: Arc<Mutex<WindowData>>,
width: usize, width: usize,
height: usize, height: usize,
factor: usize, factor: usize,
@ -32,11 +107,15 @@ pub struct WindowRenderer {
} }
impl WindowRenderer { impl WindowRenderer {
pub fn new(factor: usize, gamepad_handler: Option<Gilrs>) -> Self { pub fn new(
let event_loop = EventLoop::new(); factor: usize,
gamepad_handler: Option<Gilrs>,
input: Arc<Mutex<WinitInputHelper>>,
event_loop: &EventLoop<()>,
) -> (Self, WindowInfo) {
let window = WindowBuilder::new() let window = WindowBuilder::new()
.with_title("A fantastic window!") .with_title("Gameboy")
.build(&event_loop) .build(event_loop)
.unwrap(); .unwrap();
let real_factor = (window.scale_factor() * factor as f64) as usize; let real_factor = (window.scale_factor() * factor as f64) as usize;
@ -54,13 +133,20 @@ impl WindowRenderer {
.unwrap() .unwrap()
}; };
let input = WinitInputHelper::new(); let data = Arc::new(Mutex::new(WindowData {
scaled_buf: Vec::new(),
pixels,
}));
let info = WindowInfo {
id: window.id(),
data: data.clone(),
};
(
Self { Self {
event_loop,
window, window,
input, input,
pixels, data,
scaled_buf: vec![],
width: 0, width: 0,
height: 0, height: 0,
factor, factor,
@ -68,38 +154,9 @@ impl WindowRenderer {
gamepad_handler, gamepad_handler,
joypad_state: JoypadState::default(), joypad_state: JoypadState::default(),
current_rumble: false, current_rumble: false,
} },
} info,
)
fn update_events(&mut self) {
self.event_loop.run_return(|event, _, control_flow| {
control_flow.set_wait();
self.input.update(&event);
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
// quit = true;
}
Event::MainEventsCleared => {
control_flow.set_exit();
}
Event::RedrawRequested(_) => {
for (pixel, source) in self
.pixels
.frame_mut()
.chunks_exact_mut(4)
.zip(&self.scaled_buf)
{
pixel.copy_from_slice(source);
}
self.pixels.render().unwrap();
}
_ => {}
}
});
} }
} }
@ -113,28 +170,30 @@ impl Renderer<[u8; 4]> for WindowRenderer {
let h = (height * self.real_factor) as u32; let h = (height * self.real_factor) as u32;
self.window.set_inner_size(PhysicalSize::new(w, h)); self.window.set_inner_size(PhysicalSize::new(w, h));
self.pixels = { if let Ok(mut data) = self.data.lock() {
data.pixels = {
let window_size = self.window.inner_size(); let window_size = self.window.inner_size();
let surface_texture = let surface_texture =
SurfaceTexture::new(window_size.width, window_size.height, &self.window); SurfaceTexture::new(window_size.width, window_size.height, &self.window);
Pixels::new(window_size.width, window_size.height, surface_texture).unwrap() Pixels::new(window_size.width, window_size.height, surface_texture).unwrap()
}; };
self.scaled_buf.resize((w * h) as usize, [0; 4]); data.scaled_buf.resize((w * h) as usize, [0; 4]);
}
self.window.request_redraw(); self.window.request_redraw();
} }
fn display(&mut self, buffer: &[[u8; 4]]) { fn display(&mut self, buffer: &[[u8; 4]]) {
if let Ok(mut data) = self.data.lock() {
scale_buffer_in_place( scale_buffer_in_place(
buffer, buffer,
&mut self.scaled_buf, &mut data.scaled_buf,
self.width, self.width,
self.height, self.height,
self.real_factor, self.real_factor,
); );
}
self.window.request_redraw(); self.window.request_redraw();
self.update_events();
} }
fn set_title(&mut self, title: String) { fn set_title(&mut self, title: String) {
@ -142,7 +201,6 @@ impl Renderer<[u8; 4]> for WindowRenderer {
} }
fn latest_joypad_state(&mut self) -> JoypadState { fn latest_joypad_state(&mut self) -> JoypadState {
self.update_events();
self.joypad_state.reset(); self.joypad_state.reset();
if let Some(ref mut gamepad_handler) = self.gamepad_handler { if let Some(ref mut gamepad_handler) = self.gamepad_handler {
@ -174,19 +232,20 @@ impl Renderer<[u8; 4]> for WindowRenderer {
} }
} }
if let Ok(input) = self.input.lock() {
self.joypad_state.down |= self.joypad_state.down |=
self.input.key_held(VirtualKeyCode::Down) || self.input.key_held(VirtualKeyCode::S); input.key_held(VirtualKeyCode::Down) || input.key_held(VirtualKeyCode::S);
self.joypad_state.up |= self.joypad_state.up |=
self.input.key_held(VirtualKeyCode::Up) || self.input.key_held(VirtualKeyCode::W); input.key_held(VirtualKeyCode::Up) || input.key_held(VirtualKeyCode::W);
self.joypad_state.left |= self.joypad_state.left |=
self.input.key_held(VirtualKeyCode::Left) || self.input.key_held(VirtualKeyCode::A); input.key_held(VirtualKeyCode::Left) || input.key_held(VirtualKeyCode::A);
self.joypad_state.right |= self.joypad_state.right |=
self.input.key_held(VirtualKeyCode::Right) || self.input.key_held(VirtualKeyCode::D); input.key_held(VirtualKeyCode::Right) || input.key_held(VirtualKeyCode::D);
self.joypad_state.start |= self.input.key_held(VirtualKeyCode::Equals); self.joypad_state.start |= input.key_held(VirtualKeyCode::Equals);
self.joypad_state.select |= self.input.key_held(VirtualKeyCode::Minus); self.joypad_state.select |= input.key_held(VirtualKeyCode::Minus);
self.joypad_state.a |= self.input.key_held(VirtualKeyCode::Apostrophe); self.joypad_state.a |= input.key_held(VirtualKeyCode::Apostrophe);
self.joypad_state.b |= self.input.key_held(VirtualKeyCode::Semicolon); self.joypad_state.b |= input.key_held(VirtualKeyCode::Semicolon);
}
self.joypad_state self.joypad_state
} }