diff --git a/assets/selawk.ttf b/assets/selawik.ttf similarity index 100% rename from assets/selawk.ttf rename to assets/selawik.ttf diff --git a/src/app.rs b/src/app.rs index 4f21223..0196b15 100644 --- a/src/app.rs +++ b/src/app.rs @@ -2,7 +2,8 @@ use std::{collections::HashSet, num::NonZero, sync::Arc, thread}; use egui::{ ahash::{HashMap, HashMapExt}, - Context, TextWrapMode, ViewportBuilder, ViewportCommand, ViewportId, ViewportInfo, + Context, FontData, FontDefinitions, FontFamily, TextWrapMode, ViewportBuilder, ViewportCommand, + ViewportId, ViewportInfo, }; use gilrs::{EventType, Gilrs}; use winit::{ @@ -89,20 +90,37 @@ impl ApplicationHandler for Application { } _ => {} } + let mut queue_redraw = false; + let mut inactive_viewports = HashSet::new(); match viewport.on_window_event(event) { Some(Action::Redraw) => { 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) => { - self.viewports.remove(&viewport_id); - if viewport_id == ViewportId::ROOT { - event_loop.exit(); - } + inactive_viewports.insert(viewport_id); } 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( @@ -165,6 +183,17 @@ impl Viewport { ); 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| { s.wrap_mode = Some(TextWrapMode::Extend); s.visuals.menu_rounding = Default::default(); @@ -242,7 +271,7 @@ impl Viewport { self.state .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); }; @@ -255,6 +284,7 @@ impl Viewport { self.state = state; } self.commands.append(&mut deferred_commands); + self.commands.append(&mut viewport_output.commands); egui_winit::process_viewport_commands( &self.ctx, &mut self.info, diff --git a/src/window/game.rs b/src/window/game.rs index 23d4542..0ec7885 100644 --- a/src/window/game.rs +++ b/src/window/game.rs @@ -3,8 +3,8 @@ use crate::{ emulator::{EmulatorClient, EmulatorCommand, SimId}, }; use egui::{ - menu, Button, CentralPanel, Color32, Context, Response, TopBottomPanel, Ui, ViewportBuilder, - ViewportCommand, ViewportId, WidgetText, + menu, Button, CentralPanel, Color32, Context, Frame, Response, TopBottomPanel, Ui, + ViewportBuilder, ViewportCommand, ViewportId, WidgetText, }; use winit::event_loop::EventLoopProxy; @@ -67,7 +67,7 @@ impl GameWindow { for scale in 1..=4 { let label = format!("x{scale}"); 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 .selectable_button((current_dims - dims).length() < 1.0, label) .clicked() @@ -133,18 +133,19 @@ impl AppWindow for GameWindow { fn initial_viewport(&self) -> ViewportBuilder { ViewportBuilder::default() .with_title("Shrooms VB") - .with_inner_size((384.0, 244.0)) + .with_inner_size((384.0, 246.0)) } fn show(&mut self, ctx: &Context) { TopBottomPanel::top("menubar") - .exact_height(20.0) + .exact_height(22.0) .show(ctx, |ui| { menu::bar(ui, |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() { ui.add(screen); } diff --git a/src/window/game_screen.rs b/src/window/game_screen.rs index e1ee7dd..c70c9bc 100644 --- a/src/window/game_screen.rs +++ b/src/window/game_screen.rs @@ -171,14 +171,24 @@ struct GameScreenCallback { impl egui_wgpu::CallbackTrait for GameScreenCallback { fn paint( &self, - _info: egui::PaintCallbackInfo, + info: egui::PaintCallbackInfo, render_pass: &mut wgpu::RenderPass<'static>, callback_resources: &egui_wgpu::CallbackResources, ) { 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_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); } }