aboutsummaryrefslogtreecommitdiff
path: root/src/desktop/window.rs
diff options
context:
space:
mode:
authorAstatin <[email protected]>2025-04-03 18:35:03 +0200
committerAstatin <[email protected]>2025-04-03 18:35:03 +0200
commit9a8e4117be8d30109229600346e7d9561c52a3e3 (patch)
tree6d2531b675e609d3d5d734732f1328769dddf557 /src/desktop/window.rs
parentc1fb610e198d785aa57440b86c69587e5caaf563 (diff)
Separate core from desktop target
Diffstat (limited to 'src/desktop/window.rs')
-rw-r--r--src/desktop/window.rs125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/desktop/window.rs b/src/desktop/window.rs
new file mode 100644
index 0000000..14ac3a7
--- /dev/null
+++ b/src/desktop/window.rs
@@ -0,0 +1,125 @@
+use std::cell::RefCell;
+use std::collections::HashSet;
+use std::rc::Rc;
+use std::sync::Arc;
+use std::time::Duration;
+
+use crate::io::{WindowSignal, Window};
+
+use pixels::{Error, Pixels, SurfaceTexture};
+use winit::dpi::LogicalSize;
+use winit::event::{Event, WindowEvent};
+use winit::event_loop::EventLoop;
+use winit::keyboard::{KeyCode, PhysicalKey};
+use winit::platform::pump_events::EventLoopExtPumpEvents;
+use winit::window::{Window as WinitWindow, WindowBuilder};
+use winit_input_helper::WinitInputHelper;
+
+const WIDTH: u32 = 160;
+const HEIGHT: u32 = 144;
+
+pub type Keys = Rc<RefCell<HashSet<KeyCode>>>;
+
+pub struct DesktopWindow<'a> {
+ event_loop: EventLoop<()>,
+ input: WinitInputHelper,
+ window: Arc<WinitWindow>,
+ pixels: Pixels<'a>,
+ pub keys: Keys,
+}
+
+fn draw(frame: &mut [u8], fb: &[u32; 160 * 144]) {
+ for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
+ pixel.copy_from_slice(&((fb[i] << 8) | 0xff).to_be_bytes())
+ }
+}
+
+impl<'a> DesktopWindow<'a> {
+ pub fn new() -> Result<Self, Error> {
+ let event_loop = EventLoop::new().unwrap();
+ let input = WinitInputHelper::new();
+ let window = Arc::new({
+ let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64);
+ WindowBuilder::new()
+ .with_title("Gameboy Emulator")
+ .with_inner_size(size)
+ .with_min_inner_size(size)
+ .build(&event_loop)
+ .unwrap()
+ });
+
+ let pixels = {
+ let window_size = window.inner_size();
+ let surface_texture =
+ SurfaceTexture::new(window_size.width, window_size.height, window.clone());
+ Pixels::new(WIDTH, HEIGHT, surface_texture)?
+ };
+
+ Ok(Self {
+ event_loop,
+ input,
+ window,
+ pixels,
+ keys: Rc::new(HashSet::new().into()),
+ })
+ }
+}
+
+impl<'a> Window for DesktopWindow<'a> {
+ fn update(&mut self, fb: &[u32; 160 * 144]) -> Option<WindowSignal> {
+ let mut res = None;
+ let mut keys = (*self.keys).borrow_mut();
+ self.event_loop
+ .pump_events(Some(Duration::ZERO), |event, elwt| {
+ if let Event::WindowEvent {
+ event: WindowEvent::RedrawRequested,
+ ..
+ } = event
+ {
+ draw(self.pixels.frame_mut(), fb);
+ if let Err(err) = self.pixels.render() {
+ eprintln!("Error during render: {}", err);
+ return;
+ }
+ }
+
+ if let Event::WindowEvent {
+ window_id: _,
+ event:
+ WindowEvent::KeyboardInput {
+ device_id: _,
+ event: ref keyboard_event,
+ is_synthetic: _,
+ },
+ } = event
+ {
+ if let PhysicalKey::Code(keycode) = keyboard_event.physical_key {
+ if keyboard_event.state.is_pressed() {
+ keys.insert(keycode);
+ } else {
+ keys.remove(&keycode);
+ }
+ }
+ }
+
+ if self.input.update(&event) {
+ if self.input.close_requested() {
+ elwt.exit();
+ res = Some(WindowSignal::Exit);
+ return;
+ }
+
+ if let Some(size) = self.input.window_resized() {
+ if let Err(err) = self.pixels.resize_surface(size.width, size.height) {
+ eprintln!("Error during resize: {}", err);
+ return;
+ }
+ }
+
+ self.window.request_redraw();
+ }
+ });
+
+ res
+ }
+}