Support running two sims at once
This commit is contained in:
+42
-36
@@ -1,7 +1,4 @@
|
||||
use std::{
|
||||
sync::{Arc, RwLock},
|
||||
time::Instant,
|
||||
};
|
||||
use std::{sync::Arc, time::Instant};
|
||||
use wgpu::util::DeviceExt as _;
|
||||
use winit::{
|
||||
dpi::LogicalSize,
|
||||
@@ -11,24 +8,22 @@ use winit::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
emulator::{EmulatorClient, EmulatorCommand},
|
||||
input::InputMapper,
|
||||
emulator::{EmulatorClient, EmulatorCommand, SimId},
|
||||
renderer::GameRenderer,
|
||||
};
|
||||
|
||||
use super::{
|
||||
common::{ImguiState, WindowState, WindowStateBuilder},
|
||||
input::InputWindow,
|
||||
AppWindow, UserEvent,
|
||||
};
|
||||
|
||||
pub struct GameWindow {
|
||||
window: WindowState,
|
||||
imgui: Option<ImguiState>,
|
||||
imgui: ImguiState,
|
||||
pipeline: wgpu::RenderPipeline,
|
||||
bind_group: wgpu::BindGroup,
|
||||
sim_id: SimId,
|
||||
client: EmulatorClient,
|
||||
input_mapper: Arc<RwLock<InputMapper>>,
|
||||
proxy: EventLoopProxy<UserEvent>,
|
||||
paused_due_to_minimize: bool,
|
||||
}
|
||||
@@ -36,21 +31,29 @@ pub struct GameWindow {
|
||||
impl GameWindow {
|
||||
pub fn new(
|
||||
event_loop: &ActiveEventLoop,
|
||||
sim_id: SimId,
|
||||
client: EmulatorClient,
|
||||
input_mapper: Arc<RwLock<InputMapper>>,
|
||||
proxy: EventLoopProxy<UserEvent>,
|
||||
) -> Self {
|
||||
let title = if sim_id == SimId::Player2 {
|
||||
"Shrooms VB (Player 2)"
|
||||
} else {
|
||||
"Shrooms VB"
|
||||
};
|
||||
let window = WindowStateBuilder::new(event_loop)
|
||||
.with_title("Shrooms VB")
|
||||
.with_title(title)
|
||||
.with_inner_size(LogicalSize::new(384, 244))
|
||||
.build();
|
||||
let device = &window.device;
|
||||
|
||||
let eyes = Arc::new(GameRenderer::create_texture(device, "eye"));
|
||||
client.send_command(EmulatorCommand::SetRenderer(GameRenderer {
|
||||
queue: window.queue.clone(),
|
||||
eyes: eyes.clone(),
|
||||
}));
|
||||
client.send_command(EmulatorCommand::SetRenderer(
|
||||
sim_id,
|
||||
GameRenderer {
|
||||
queue: window.queue.clone(),
|
||||
eyes: eyes.clone(),
|
||||
},
|
||||
));
|
||||
let eyes = eyes.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default());
|
||||
let colors = Colors {
|
||||
@@ -158,13 +161,15 @@ impl GameWindow {
|
||||
cache: None,
|
||||
});
|
||||
|
||||
let imgui = ImguiState::new(&window);
|
||||
|
||||
Self {
|
||||
window,
|
||||
imgui: None,
|
||||
imgui,
|
||||
pipeline: render_pipeline,
|
||||
bind_group,
|
||||
sim_id,
|
||||
client,
|
||||
input_mapper,
|
||||
proxy,
|
||||
paused_due_to_minimize: false,
|
||||
}
|
||||
@@ -172,7 +177,7 @@ impl GameWindow {
|
||||
|
||||
fn draw(&mut self, event_loop: &ActiveEventLoop) {
|
||||
let window = &mut self.window;
|
||||
let imgui = self.imgui.as_mut().unwrap();
|
||||
let imgui = &mut self.imgui;
|
||||
let mut context = imgui.context.lock().unwrap();
|
||||
let mut new_size = None;
|
||||
|
||||
@@ -204,7 +209,8 @@ impl GameWindow {
|
||||
.show_open_single_file()
|
||||
.unwrap();
|
||||
if let Some(path) = rom {
|
||||
self.client.send_command(EmulatorCommand::LoadGame(path));
|
||||
self.client
|
||||
.send_command(EmulatorCommand::LoadGame(self.sim_id, path));
|
||||
}
|
||||
}
|
||||
if ui.menu_item("Quit") {
|
||||
@@ -240,14 +246,14 @@ impl GameWindow {
|
||||
});
|
||||
ui.menu("Input", || {
|
||||
if ui.menu_item("Bind Inputs") {
|
||||
let input_window = Box::new(InputWindow::new(
|
||||
event_loop,
|
||||
self.input_mapper.clone(),
|
||||
self.proxy.clone(),
|
||||
));
|
||||
self.proxy
|
||||
.send_event(UserEvent::OpenWindow(input_window))
|
||||
.unwrap();
|
||||
self.proxy.send_event(UserEvent::OpenInputWindow).unwrap();
|
||||
}
|
||||
});
|
||||
ui.menu("Multiplayer", || {
|
||||
if self.sim_id == SimId::Player1 && ui.menu_item("Open Player 2") {
|
||||
self.client
|
||||
.send_command(EmulatorCommand::StartSecondSim(None));
|
||||
self.proxy.send_event(UserEvent::OpenPlayer2Window).unwrap();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -321,11 +327,6 @@ impl AppWindow for GameWindow {
|
||||
self.window.window.id()
|
||||
}
|
||||
|
||||
fn init(&mut self) {
|
||||
self.imgui = Some(ImguiState::new(&self.window));
|
||||
self.window.window.request_redraw();
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, event_loop: &ActiveEventLoop, event: &Event<UserEvent>) {
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
@@ -341,7 +342,14 @@ impl AppWindow for GameWindow {
|
||||
self.paused_due_to_minimize = false;
|
||||
}
|
||||
}
|
||||
WindowEvent::CloseRequested => event_loop.exit(),
|
||||
WindowEvent::CloseRequested => {
|
||||
if self.sim_id == SimId::Player2 {
|
||||
self.client.send_command(EmulatorCommand::StopSecondSim);
|
||||
self.proxy.send_event(UserEvent::Close(self.id())).unwrap();
|
||||
} else {
|
||||
event_loop.exit();
|
||||
}
|
||||
}
|
||||
WindowEvent::RedrawRequested => self.draw(event_loop),
|
||||
_ => (),
|
||||
},
|
||||
@@ -351,9 +359,7 @@ impl AppWindow for GameWindow {
|
||||
_ => (),
|
||||
}
|
||||
let window = &self.window;
|
||||
let Some(imgui) = self.imgui.as_mut() else {
|
||||
return;
|
||||
};
|
||||
let imgui = &mut self.imgui;
|
||||
let mut context = imgui.context.lock().unwrap();
|
||||
imgui
|
||||
.platform
|
||||
|
||||
+25
-26
@@ -7,10 +7,12 @@ use winit::{
|
||||
dpi::LogicalSize,
|
||||
event::{Event, KeyEvent, WindowEvent},
|
||||
event_loop::{ActiveEventLoop, EventLoopProxy},
|
||||
platform::modifier_supplement::KeyEventExtModifierSupplement,
|
||||
};
|
||||
|
||||
use crate::{input::InputMapper, shrooms_vb_core::VBKey};
|
||||
use crate::{
|
||||
emulator::{SimId, VBKey},
|
||||
input::InputMapper,
|
||||
};
|
||||
|
||||
use super::{
|
||||
common::{ImguiState, UiExt, WindowState, WindowStateBuilder},
|
||||
@@ -19,10 +21,10 @@ use super::{
|
||||
|
||||
pub struct InputWindow {
|
||||
window: WindowState,
|
||||
imgui: Option<ImguiState>,
|
||||
imgui: ImguiState,
|
||||
input_mapper: Arc<RwLock<InputMapper>>,
|
||||
proxy: EventLoopProxy<UserEvent>,
|
||||
now_binding: Option<VBKey>,
|
||||
now_binding: Option<(SimId, VBKey)>,
|
||||
}
|
||||
|
||||
const KEY_NAMES: [(VBKey, &str); 14] = [
|
||||
@@ -52,9 +54,10 @@ impl InputWindow {
|
||||
.with_title("Bind Inputs")
|
||||
.with_inner_size(LogicalSize::new(600, 400))
|
||||
.build();
|
||||
let imgui = ImguiState::new(&window);
|
||||
Self {
|
||||
window,
|
||||
imgui: None,
|
||||
imgui,
|
||||
input_mapper,
|
||||
now_binding: None,
|
||||
proxy,
|
||||
@@ -63,7 +66,7 @@ impl InputWindow {
|
||||
|
||||
fn draw(&mut self) {
|
||||
let window = &mut self.window;
|
||||
let imgui = self.imgui.as_mut().unwrap();
|
||||
let imgui = &mut self.imgui;
|
||||
let mut context = imgui.context.lock().unwrap();
|
||||
|
||||
let now = Instant::now();
|
||||
@@ -85,11 +88,11 @@ impl InputWindow {
|
||||
.expect("Failed to prepare frame");
|
||||
let ui = context.new_frame();
|
||||
|
||||
let mut render_key_bindings = || {
|
||||
let mut render_key_bindings = |sim_id: SimId| {
|
||||
if let Some(table) = ui.begin_table("controls", 2) {
|
||||
let binding_names = {
|
||||
let mapper = self.input_mapper.read().unwrap();
|
||||
mapper.binding_names()
|
||||
mapper.binding_names(&sim_id)
|
||||
};
|
||||
ui.table_next_row();
|
||||
|
||||
@@ -100,20 +103,20 @@ impl InputWindow {
|
||||
ui.group(|| {
|
||||
ui.right_align_text(name, space * 0.20);
|
||||
ui.same_line();
|
||||
let label_text = if self.now_binding == Some(key) {
|
||||
let label_text = if self.now_binding == Some((sim_id, key)) {
|
||||
"Press any input"
|
||||
} else {
|
||||
binding.unwrap_or("")
|
||||
};
|
||||
let label = format!("{}##{}", label_text, name);
|
||||
if ui.button_with_size(label, [space * 0.60, 0.0]) {
|
||||
self.now_binding = Some(key);
|
||||
self.now_binding = Some((sim_id, key));
|
||||
}
|
||||
});
|
||||
ui.same_line();
|
||||
if ui.button(format!("Clear##{name}")) {
|
||||
let mut mapper = self.input_mapper.write().unwrap();
|
||||
mapper.clear_binding(key);
|
||||
mapper.clear_binding(sim_id, key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +127,11 @@ impl InputWindow {
|
||||
if let Some(window) = ui.fullscreen_window() {
|
||||
if let Some(tabs) = ui.tab_bar("tabs") {
|
||||
if let Some(tab) = ui.tab_item("Player 1") {
|
||||
render_key_bindings();
|
||||
render_key_bindings(SimId::Player1);
|
||||
tab.end();
|
||||
}
|
||||
if let Some(tab) = ui.tab_item("Player 2") {
|
||||
render_key_bindings(SimId::Player2);
|
||||
tab.end();
|
||||
}
|
||||
tabs.end();
|
||||
@@ -175,11 +182,11 @@ impl InputWindow {
|
||||
if !event.state.is_pressed() {
|
||||
return;
|
||||
}
|
||||
let Some(vb) = self.now_binding.take() else {
|
||||
let Some((sim_id, vb)) = self.now_binding.take() else {
|
||||
return;
|
||||
};
|
||||
let mut mapper = self.input_mapper.write().unwrap();
|
||||
mapper.bind_key(vb, event.key_without_modifiers());
|
||||
mapper.bind_key(sim_id, vb, event.physical_key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,19 +195,13 @@ impl AppWindow for InputWindow {
|
||||
self.window.window.id()
|
||||
}
|
||||
|
||||
fn init(&mut self) {
|
||||
self.imgui = Some(ImguiState::new(&self.window));
|
||||
self.window.window.request_redraw();
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, _: &ActiveEventLoop, event: &Event<UserEvent>) {
|
||||
match event {
|
||||
Event::WindowEvent { event, .. } => match event {
|
||||
WindowEvent::Resized(size) => self.window.handle_resize(size),
|
||||
WindowEvent::CloseRequested => self
|
||||
.proxy
|
||||
.send_event(UserEvent::CloseWindow(self.id()))
|
||||
.unwrap(),
|
||||
WindowEvent::CloseRequested => {
|
||||
self.proxy.send_event(UserEvent::Close(self.id())).unwrap()
|
||||
}
|
||||
WindowEvent::KeyboardInput { event, .. } => self.try_bind_key(event),
|
||||
WindowEvent::RedrawRequested => self.draw(),
|
||||
_ => (),
|
||||
@@ -212,9 +213,7 @@ impl AppWindow for InputWindow {
|
||||
}
|
||||
|
||||
let window = &self.window;
|
||||
let Some(imgui) = self.imgui.as_mut() else {
|
||||
return;
|
||||
};
|
||||
let imgui = &mut self.imgui;
|
||||
let mut context = imgui.context.lock().unwrap();
|
||||
imgui
|
||||
.platform
|
||||
|
||||
Reference in New Issue
Block a user