fix windows
This commit is contained in:
parent
9e836927c4
commit
429e3b4085
2 changed files with 234 additions and 150 deletions
|
@ -11,8 +11,11 @@ use gb_emu_lib::{
|
|||
EmulatorCore,
|
||||
};
|
||||
use gilrs::Gilrs;
|
||||
use std::sync::mpsc::channel;
|
||||
use window::WindowRenderer;
|
||||
use std::{
|
||||
sync::mpsc::channel,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use window::{WindowManager, WindowRenderer};
|
||||
|
||||
mod audio;
|
||||
#[cfg(feature = "camera")]
|
||||
|
@ -75,18 +78,28 @@ struct Args {
|
|||
fn main() {
|
||||
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 {
|
||||
factor
|
||||
} else {
|
||||
3
|
||||
};
|
||||
|
||||
let tile_window: Option<WindowRenderer> = if args.tile_window {
|
||||
Some(WindowRenderer::new(factor, None))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let (sender, receiver) = channel::<EmulatorMessage>();
|
||||
let (debug_sender, debug_receiver) = channel::<EmulatorMessage>();
|
||||
|
||||
|
@ -97,10 +110,17 @@ fn main() {
|
|||
.unwrap();
|
||||
|
||||
let (output, _stream) = audio::create_output(args.mute);
|
||||
|
||||
let window = WindowRenderer::new(factor, Some(Gilrs::new().unwrap()));
|
||||
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)
|
||||
.with_save_path(args.save)
|
||||
.with_serial_target(if args.connect_serial {
|
||||
|
@ -125,27 +145,32 @@ fn main() {
|
|||
#[cfg(feature = "camera")]
|
||||
let core = Box::new(EmulatorCore::init(receiver, options, Webcam::new()));
|
||||
|
||||
let mut handler = if args.debug {
|
||||
EmulatorHandler::Debug(Debugger::new(core, debug_receiver))
|
||||
let emu = if args.debug {
|
||||
EmulatorTypes::Debug(Debugger::new(core, debug_receiver))
|
||||
} else {
|
||||
EmulatorHandler::Normal(core)
|
||||
EmulatorTypes::Normal(core)
|
||||
};
|
||||
|
||||
let since = Instant::now();
|
||||
|
||||
let mut h = Self {
|
||||
emu,
|
||||
window_manager,
|
||||
since,
|
||||
};
|
||||
loop {
|
||||
handler.run();
|
||||
h.cycle();
|
||||
}
|
||||
}
|
||||
|
||||
enum EmulatorHandler {
|
||||
Debug(Debugger),
|
||||
Normal(Box<dyn EmulatorCoreTrait>),
|
||||
fn cycle(&mut self) {
|
||||
if self.since.elapsed() >= Duration::from_millis(10) {
|
||||
self.window_manager.update_events();
|
||||
self.since = Instant::now();
|
||||
}
|
||||
|
||||
impl EmulatorHandler {
|
||||
fn run(&mut self) {
|
||||
match self {
|
||||
EmulatorHandler::Debug(ref mut debugger) => debugger.step(),
|
||||
EmulatorHandler::Normal(ref mut core) => core.run(),
|
||||
match self.emu {
|
||||
EmulatorTypes::Debug(ref mut debugger) => debugger.step(),
|
||||
EmulatorTypes::Normal(ref mut core) => core.run(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use gb_emu_lib::{
|
||||
connect::{JoypadState, Renderer},
|
||||
util::scale_buffer_in_place,
|
||||
|
@ -12,16 +17,86 @@ use winit::{
|
|||
event::{Event, VirtualKeyCode, WindowEvent},
|
||||
event_loop::EventLoop,
|
||||
platform::run_return::EventLoopExtRunReturn,
|
||||
window::{Window, WindowBuilder},
|
||||
window::{Window, WindowBuilder, WindowId},
|
||||
};
|
||||
use winit_input_helper::WinitInputHelper;
|
||||
|
||||
pub struct WindowRenderer {
|
||||
event_loop: EventLoop<()>,
|
||||
window: Window,
|
||||
input: WinitInputHelper,
|
||||
pixels: Pixels,
|
||||
pub struct WindowInfo {
|
||||
id: WindowId,
|
||||
data: Arc<Mutex<WindowData>>,
|
||||
}
|
||||
|
||||
pub struct WindowData {
|
||||
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,
|
||||
height: usize,
|
||||
factor: usize,
|
||||
|
@ -32,11 +107,15 @@ pub struct WindowRenderer {
|
|||
}
|
||||
|
||||
impl WindowRenderer {
|
||||
pub fn new(factor: usize, gamepad_handler: Option<Gilrs>) -> Self {
|
||||
let event_loop = EventLoop::new();
|
||||
pub fn new(
|
||||
factor: usize,
|
||||
gamepad_handler: Option<Gilrs>,
|
||||
input: Arc<Mutex<WinitInputHelper>>,
|
||||
event_loop: &EventLoop<()>,
|
||||
) -> (Self, WindowInfo) {
|
||||
let window = WindowBuilder::new()
|
||||
.with_title("A fantastic window!")
|
||||
.build(&event_loop)
|
||||
.with_title("Gameboy")
|
||||
.build(event_loop)
|
||||
.unwrap();
|
||||
|
||||
let real_factor = (window.scale_factor() * factor as f64) as usize;
|
||||
|
@ -54,13 +133,20 @@ impl WindowRenderer {
|
|||
.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 {
|
||||
event_loop,
|
||||
window,
|
||||
input,
|
||||
pixels,
|
||||
scaled_buf: vec![],
|
||||
data,
|
||||
width: 0,
|
||||
height: 0,
|
||||
factor,
|
||||
|
@ -68,38 +154,9 @@ impl WindowRenderer {
|
|||
gamepad_handler,
|
||||
joypad_state: JoypadState::default(),
|
||||
current_rumble: false,
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
});
|
||||
},
|
||||
info,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,28 +170,30 @@ impl Renderer<[u8; 4]> for WindowRenderer {
|
|||
let h = (height * self.real_factor) as u32;
|
||||
|
||||
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 surface_texture =
|
||||
SurfaceTexture::new(window_size.width, window_size.height, &self.window);
|
||||
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();
|
||||
}
|
||||
|
||||
fn display(&mut self, buffer: &[[u8; 4]]) {
|
||||
if let Ok(mut data) = self.data.lock() {
|
||||
scale_buffer_in_place(
|
||||
buffer,
|
||||
&mut self.scaled_buf,
|
||||
&mut data.scaled_buf,
|
||||
self.width,
|
||||
self.height,
|
||||
self.real_factor,
|
||||
);
|
||||
}
|
||||
self.window.request_redraw();
|
||||
self.update_events();
|
||||
}
|
||||
|
||||
fn set_title(&mut self, title: String) {
|
||||
|
@ -142,7 +201,6 @@ impl Renderer<[u8; 4]> for WindowRenderer {
|
|||
}
|
||||
|
||||
fn latest_joypad_state(&mut self) -> JoypadState {
|
||||
self.update_events();
|
||||
self.joypad_state.reset();
|
||||
|
||||
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.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.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.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.input.key_held(VirtualKeyCode::Right) || self.input.key_held(VirtualKeyCode::D);
|
||||
self.joypad_state.start |= self.input.key_held(VirtualKeyCode::Equals);
|
||||
self.joypad_state.select |= self.input.key_held(VirtualKeyCode::Minus);
|
||||
self.joypad_state.a |= self.input.key_held(VirtualKeyCode::Apostrophe);
|
||||
self.joypad_state.b |= self.input.key_held(VirtualKeyCode::Semicolon);
|
||||
|
||||
input.key_held(VirtualKeyCode::Right) || input.key_held(VirtualKeyCode::D);
|
||||
self.joypad_state.start |= input.key_held(VirtualKeyCode::Equals);
|
||||
self.joypad_state.select |= input.key_held(VirtualKeyCode::Minus);
|
||||
self.joypad_state.a |= input.key_held(VirtualKeyCode::Apostrophe);
|
||||
self.joypad_state.b |= input.key_held(VirtualKeyCode::Semicolon);
|
||||
}
|
||||
self.joypad_state
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue