diff --git a/src/lib.rs b/src/lib.rs index ddb0732..c5ab6e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,8 @@ pub struct PlatformConfig { pub aspect_ratio: Option, pub palette: [[u8; 3]; 256], pub vsync: bool, + pub mouse_visible: bool, + pub mouse_capture: bool, } impl Default for PlatformConfig { @@ -27,6 +29,8 @@ impl Default for PlatformConfig { aspect_ratio: Some(4.0 / 3.0), palette: palette::RGB332, vsync: true, + mouse_visible: true, + mouse_capture: false, } } } @@ -99,6 +103,13 @@ pub struct Platform { event_queue: VecDeque, event_scratch: Vec, close_requested: bool, + + mouse_visible: bool, + mouse_capture: bool, + // Letzte rohe (window-space) Cursorposition, um Deltas zu bilden. None nach + // Mode-Wechsel/erstem Frame, damit der GLFW-Recenter keinen Riesensprung erzeugt. + last_cursor_pos: Option<(f64, f64)>, + mouse_delta: (f32, f32), } impl Platform { @@ -203,7 +214,7 @@ impl Platform { ], }); - Self { + let mut platform = Self { bind_group, pipeline, index_tex, palette_tex, params_buf, params, surface, config: surface_config, device, queue, instance, window, events, glfw, @@ -213,7 +224,41 @@ impl Platform { event_queue: VecDeque::new(), event_scratch: Vec::new(), close_requested: false, - } + mouse_visible: cfg.mouse_visible, + mouse_capture: cfg.mouse_capture, + last_cursor_pos: None, + mouse_delta: (0.0, 0.0), + }; + platform.apply_cursor_mode(); + platform + } + + pub fn set_mouse_visible(&mut self, visible: bool) { + self.mouse_visible = visible; + self.apply_cursor_mode(); + } + + pub fn set_mouse_capture(&mut self, capture: bool) { + self.mouse_capture = capture; + // Recenter nach Mode-Wechsel würde den nächsten Delta springen lassen. + self.last_cursor_pos = None; + self.apply_cursor_mode(); + } + + fn apply_cursor_mode(&mut self) { + // capture impliziert hidden — GLFW kennt keinen "locked + visible". + let mode = match (self.mouse_capture, self.mouse_visible) { + (true, _) => glfw::CursorMode::Disabled, + (false, true) => glfw::CursorMode::Normal, + (false, false) => glfw::CursorMode::Hidden, + }; + self.window.set_cursor_mode(mode); + } + + /// Akkumulierte Mausbewegung seit dem letzten Aufruf, in Window-Pixeln. + /// Bei `set_mouse_capture(true)` liefert GLFW unbegrenzte Deltas (FPS-Stil). + pub fn mouse_delta(&mut self) -> (f32, f32) { + std::mem::replace(&mut self.mouse_delta, (0.0, 0.0)) } pub fn should_close(&self) -> bool { self.close_requested || self.window.should_close() } @@ -312,6 +357,12 @@ impl Platform { } W::Char(c) => self.event_queue.push_back(Event::Char(c)), W::CursorPos(x, y) => { + if let Some((lx, ly)) = self.last_cursor_pos { + self.mouse_delta.0 += (x - lx) as f32; + self.mouse_delta.1 += (y - ly) as f32; + } + self.last_cursor_pos = Some((x, y)); + let (cx, cy, cw, ch) = self.content_rect; let (fw, fh) = self.framebuffer_size; let fx = ((x - cx as f64) / cw as f64 * fw as f64) as f32;