Implement multiplayer #2

Merged
SonicSwordcane merged 21 commits from multiplayer into main 2024-11-30 00:31:10 +00:00
4 changed files with 56 additions and 15 deletions
Showing only changes of commit 9ff62af310 - Show all commits

View File

@ -2,7 +2,8 @@ use std::{collections::HashSet, num::NonZero, sync::Arc, thread};
use egui::{ use egui::{
ahash::{HashMap, HashMapExt}, ahash::{HashMap, HashMapExt},
Context, TextWrapMode, ViewportBuilder, ViewportCommand, ViewportId, ViewportInfo, Context, FontData, FontDefinitions, FontFamily, TextWrapMode, ViewportBuilder, ViewportCommand,
ViewportId, ViewportInfo,
}; };
use gilrs::{EventType, Gilrs}; use gilrs::{EventType, Gilrs};
use winit::{ use winit::{
@ -89,20 +90,37 @@ impl ApplicationHandler<UserEvent> for Application {
} }
_ => {} _ => {}
} }
let mut queue_redraw = false;
let mut inactive_viewports = HashSet::new();
match viewport.on_window_event(event) { match viewport.on_window_event(event) {
Some(Action::Redraw) => { Some(Action::Redraw) => {
for viewport in self.viewports.values_mut() { for viewport in self.viewports.values_mut() {
viewport.redraw(event_loop); match viewport.redraw(event_loop) {
Some(Action::Redraw) => {
queue_redraw = true;
}
Some(Action::Close) => {
inactive_viewports.insert(viewport.id());
}
None => {}
}
} }
} }
Some(Action::Close) => { Some(Action::Close) => {
self.viewports.remove(&viewport_id); inactive_viewports.insert(viewport_id);
if viewport_id == ViewportId::ROOT {
event_loop.exit();
}
} }
None => {} None => {}
} }
self.viewports
.retain(|k, _| !inactive_viewports.contains(k));
match self.viewports.get(&ViewportId::ROOT) {
Some(viewport) => {
if queue_redraw {
viewport.window.request_redraw();
}
}
None => event_loop.exit(),
}
} }
fn device_event( fn device_event(
@ -165,6 +183,17 @@ impl Viewport {
); );
let ctx = Context::default(); let ctx = Context::default();
let mut fonts = FontDefinitions::empty();
fonts.font_data.insert(
"Selawik".into(),
FontData::from_static(include_bytes!("../assets/selawik.ttf")),
);
fonts
.families
.get_mut(&FontFamily::Proportional)
.unwrap()
.insert(0, "Selawik".into());
ctx.set_fonts(fonts);
ctx.style_mut(|s| { ctx.style_mut(|s| {
s.wrap_mode = Some(TextWrapMode::Extend); s.wrap_mode = Some(TextWrapMode::Extend);
s.visuals.menu_rounding = Default::default(); s.visuals.menu_rounding = Default::default();
@ -242,7 +271,7 @@ impl Viewport {
self.state self.state
.handle_platform_output(&self.window, output.platform_output); .handle_platform_output(&self.window, output.platform_output);
let Some(viewport_output) = output.viewport_output.remove(&ViewportId::ROOT) else { let Some(mut viewport_output) = output.viewport_output.remove(&ViewportId::ROOT) else {
return Some(Action::Close); return Some(Action::Close);
}; };
@ -255,6 +284,7 @@ impl Viewport {
self.state = state; self.state = state;
} }
self.commands.append(&mut deferred_commands); self.commands.append(&mut deferred_commands);
self.commands.append(&mut viewport_output.commands);
egui_winit::process_viewport_commands( egui_winit::process_viewport_commands(
&self.ctx, &self.ctx,
&mut self.info, &mut self.info,

View File

@ -3,8 +3,8 @@ use crate::{
emulator::{EmulatorClient, EmulatorCommand, SimId}, emulator::{EmulatorClient, EmulatorCommand, SimId},
}; };
use egui::{ use egui::{
menu, Button, CentralPanel, Color32, Context, Response, TopBottomPanel, Ui, ViewportBuilder, menu, Button, CentralPanel, Color32, Context, Frame, Response, TopBottomPanel, Ui,
ViewportCommand, ViewportId, WidgetText, ViewportBuilder, ViewportCommand, ViewportId, WidgetText,
}; };
use winit::event_loop::EventLoopProxy; use winit::event_loop::EventLoopProxy;
@ -67,7 +67,7 @@ impl GameWindow {
for scale in 1..=4 { for scale in 1..=4 {
let label = format!("x{scale}"); let label = format!("x{scale}");
let scale = scale as f32; let scale = scale as f32;
let dims = (384.0 * scale, 224.0 * scale + 20.0).into(); let dims = (384.0 * scale, 224.0 * scale + 22.0).into();
if ui if ui
.selectable_button((current_dims - dims).length() < 1.0, label) .selectable_button((current_dims - dims).length() < 1.0, label)
.clicked() .clicked()
@ -133,18 +133,19 @@ impl AppWindow for GameWindow {
fn initial_viewport(&self) -> ViewportBuilder { fn initial_viewport(&self) -> ViewportBuilder {
ViewportBuilder::default() ViewportBuilder::default()
.with_title("Shrooms VB") .with_title("Shrooms VB")
.with_inner_size((384.0, 244.0)) .with_inner_size((384.0, 246.0))
} }
fn show(&mut self, ctx: &Context) { fn show(&mut self, ctx: &Context) {
TopBottomPanel::top("menubar") TopBottomPanel::top("menubar")
.exact_height(20.0) .exact_height(22.0)
.show(ctx, |ui| { .show(ctx, |ui| {
menu::bar(ui, |ui| { menu::bar(ui, |ui| {
self.show_menu(ctx, ui); self.show_menu(ctx, ui);
}); });
}); });
CentralPanel::default().show(ctx, |ui| { let frame = Frame::central_panel(&ctx.style()).fill(Color32::BLACK);
CentralPanel::default().frame(frame).show(ctx, |ui| {
if let Some(screen) = self.screen.as_ref() { if let Some(screen) = self.screen.as_ref() {
ui.add(screen); ui.add(screen);
} }

View File

@ -171,14 +171,24 @@ struct GameScreenCallback {
impl egui_wgpu::CallbackTrait for GameScreenCallback { impl egui_wgpu::CallbackTrait for GameScreenCallback {
fn paint( fn paint(
&self, &self,
_info: egui::PaintCallbackInfo, info: egui::PaintCallbackInfo,
render_pass: &mut wgpu::RenderPass<'static>, render_pass: &mut wgpu::RenderPass<'static>,
callback_resources: &egui_wgpu::CallbackResources, callback_resources: &egui_wgpu::CallbackResources,
) { ) {
let resources: &SharedGameScreenResources = callback_resources.get().unwrap(); let resources: &SharedGameScreenResources = callback_resources.get().unwrap();
// TODO: maintain aspect ratio let viewport = info.viewport_in_pixels();
let left = viewport.left_px as f32;
let top = viewport.top_px as f32;
let width = viewport.width_px as f32;
let height = viewport.height_px as f32;
let aspect_ratio = 384.0 / 224.0;
let w = width.min(height * aspect_ratio);
let h = height.min(width / aspect_ratio);
let x = left + (width - w) / 2.0;
let y = top + (height - h) / 2.0;
render_pass.set_pipeline(&resources.pipeline); render_pass.set_pipeline(&resources.pipeline);
render_pass.set_bind_group(0, &self.bind_group, &[]); render_pass.set_bind_group(0, &self.bind_group, &[]);
render_pass.set_viewport(x, y, w, h, 0.0, 1.0);
render_pass.draw(0..6, 0..1); render_pass.draw(0..6, 0..1);
} }
} }