158 lines
4.8 KiB
Rust
158 lines
4.8 KiB
Rust
|
use std::{
|
||
|
sync::{
|
||
|
atomic::{AtomicBool, Ordering},
|
||
|
Arc, Mutex,
|
||
|
},
|
||
|
thread,
|
||
|
};
|
||
|
|
||
|
use egui::{Context, ViewportBuilder, ViewportId};
|
||
|
use game::GameWindow;
|
||
|
use game_screen::GameScreen;
|
||
|
use gilrs::{EventType, Gilrs};
|
||
|
use input::InputWindow;
|
||
|
use winit::{event::KeyEvent, event_loop::EventLoopProxy};
|
||
|
|
||
|
use crate::{
|
||
|
application::UserEvent,
|
||
|
controller::ControllerManager,
|
||
|
emulator::{EmulatorClient, EmulatorCommand, SimId},
|
||
|
input::MappingProvider,
|
||
|
};
|
||
|
|
||
|
mod game;
|
||
|
mod game_screen;
|
||
|
mod input;
|
||
|
|
||
|
pub struct WindowManager {
|
||
|
p1: GameWindow,
|
||
|
p2: Arc<Mutex<GameWindow>>,
|
||
|
client: EmulatorClient,
|
||
|
input: ChildWindow<InputWindow>,
|
||
|
controllers: ControllerManager,
|
||
|
}
|
||
|
impl WindowManager {
|
||
|
pub fn new(client: EmulatorClient, proxy: EventLoopProxy<UserEvent>) -> Self {
|
||
|
let mappings = MappingProvider::new();
|
||
|
let controllers = ControllerManager::new(client.clone(), &mappings);
|
||
|
{
|
||
|
let mappings = mappings.clone();
|
||
|
thread::spawn(|| process_gamepad_input(mappings, proxy));
|
||
|
}
|
||
|
let input = ChildWindow::new(InputWindow::new(mappings));
|
||
|
let p1 = GameWindow::new(client.clone(), SimId::Player1, input.open.clone());
|
||
|
let p2 = GameWindow::new(client.clone(), SimId::Player2, input.open.clone());
|
||
|
Self {
|
||
|
p1,
|
||
|
p2: Arc::new(Mutex::new(p2)),
|
||
|
client,
|
||
|
input,
|
||
|
controllers,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn init_renderer(&mut self, render_state: &egui_wgpu::RenderState) {
|
||
|
GameScreen::init_pipeline(render_state);
|
||
|
self.p2.lock().unwrap().init_renderer(render_state);
|
||
|
self.p1.init_renderer(render_state);
|
||
|
}
|
||
|
|
||
|
pub fn initial_viewport(&self) -> ViewportBuilder {
|
||
|
self.p1.initial_viewport()
|
||
|
}
|
||
|
|
||
|
pub fn show(&mut self, ctx: &Context) {
|
||
|
self.p1.show(ctx);
|
||
|
self.input.show(ctx);
|
||
|
if self.client.has_player_2() {
|
||
|
let (viewport_id, viewport) = {
|
||
|
let p2 = self.p2.lock().unwrap();
|
||
|
(p2.viewport_id(), p2.initial_viewport())
|
||
|
};
|
||
|
let client = self.client.clone();
|
||
|
let p2 = self.p2.clone();
|
||
|
ctx.show_viewport_deferred(viewport_id, viewport, move |ctx, _| {
|
||
|
p2.lock().unwrap().show(ctx);
|
||
|
if ctx.input(|i| i.viewport().close_requested()) {
|
||
|
client.send_command(EmulatorCommand::StopSecondSim);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn handle_key_event(&mut self, event: winit::event::KeyEvent) {
|
||
|
self.controllers.handle_key_event(&event);
|
||
|
self.input.handle_key_event(&event);
|
||
|
}
|
||
|
|
||
|
pub fn handle_gamepad_event(&mut self, event: gilrs::Event) {
|
||
|
self.controllers.handle_gamepad_event(&event);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn process_gamepad_input(mappings: MappingProvider, proxy: EventLoopProxy<UserEvent>) {
|
||
|
let Ok(mut gilrs) = Gilrs::new() else {
|
||
|
eprintln!("could not connect gamepad listener");
|
||
|
return;
|
||
|
};
|
||
|
while let Some(event) = gilrs.next_event_blocking(None) {
|
||
|
if event.event == EventType::Connected {
|
||
|
let Some(gamepad) = gilrs.connected_gamepad(event.id) else {
|
||
|
continue;
|
||
|
};
|
||
|
mappings.map_gamepad(SimId::Player1, &gamepad);
|
||
|
}
|
||
|
if proxy.send_event(UserEvent::GamepadEvent(event)).is_err() {
|
||
|
// main thread has closed! we done
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
trait AppWindow {
|
||
|
fn viewport_id(&self) -> ViewportId;
|
||
|
fn initial_viewport(&self) -> ViewportBuilder;
|
||
|
fn show(&mut self, ctx: &Context);
|
||
|
fn handle_key_event(&mut self, event: &KeyEvent) {
|
||
|
let _ = event;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
struct ChildWindow<T: AppWindow> {
|
||
|
pub open: Arc<AtomicBool>,
|
||
|
window: Arc<Mutex<T>>,
|
||
|
}
|
||
|
impl<T: AppWindow + Send + 'static> ChildWindow<T> {
|
||
|
fn new(window: T) -> Self {
|
||
|
Self {
|
||
|
open: Arc::new(AtomicBool::new(false)),
|
||
|
window: Arc::new(Mutex::new(window)),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn show(&self, ctx: &Context) {
|
||
|
if !self.open.load(Ordering::Relaxed) {
|
||
|
return;
|
||
|
}
|
||
|
let (viewport_id, viewport) = {
|
||
|
let window = self.window.lock().unwrap();
|
||
|
(window.viewport_id(), window.initial_viewport())
|
||
|
};
|
||
|
let open = self.open.clone();
|
||
|
let window = self.window.clone();
|
||
|
ctx.show_viewport_deferred(viewport_id, viewport, move |ctx, _| {
|
||
|
window.lock().unwrap().show(ctx);
|
||
|
if ctx.input(|i| i.viewport().close_requested()) {
|
||
|
open.store(false, Ordering::Relaxed);
|
||
|
ctx.request_repaint();
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
fn handle_key_event(&self, event: &KeyEvent) {
|
||
|
if self.open.load(Ordering::Relaxed) {
|
||
|
self.window.lock().unwrap().handle_key_event(event);
|
||
|
}
|
||
|
}
|
||
|
}
|