lemur/src/window.rs

158 lines
4.8 KiB
Rust
Raw Normal View History

2024-11-26 05:38:03 +00:00
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);
}
}
}