diff --git a/src/input.rs b/src/input.rs index 2dccc4613ef3dc878732a95f9749b46714bd0fcf..aa3d228aa05f43d4ef44638d755dc36f7c481897 100644 --- a/src/input.rs +++ b/src/input.rs @@ -12,6 +12,7 @@ use crate::{ event_dispatcher::EventDispatcher, input_event::InputEvent, }; +use crate::unproject::UnprojectManager; pub(crate) fn process_events(world: &mut World) { let mut input_events = Vec::new(); @@ -28,6 +29,7 @@ pub(crate) fn process_events(world: &mut World) { ResMut<CustomEventReader<MouseWheel>>, ResMut<CustomEventReader<ReceivedCharacter>>, ResMut<CustomEventReader<KeyboardInput>>, + UnprojectManager, ), _, _, @@ -43,6 +45,7 @@ pub(crate) fn process_events(world: &mut World) { mut custom_event_mouse_wheel, mut custom_event_char_input, mut custom_event_keyboard, + projector, )| { if let Some(event) = custom_event_reader_cursor .0 @@ -50,7 +53,9 @@ pub(crate) fn process_events(world: &mut World) { .last() { // Currently, we can only handle a single MouseMoved event at a time so everything but the last needs to be skipped - input_events.push(InputEvent::MouseMoved(event.position.into())); + if let Ok(pos) = projector.unproject(event.position) { + input_events.push(InputEvent::MouseMoved(pos.into())); + } } for event in custom_event_mouse_button.0.read(&mouse_button_input_events) { diff --git a/src/lib.rs b/src/lib.rs index 0929cb70b4eb0d1a3d1b441c2d89cb6918a06227..12cbb1f791c50d5d92986126960c828d46544bd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,8 @@ mod widget_state; pub mod widgets; mod window_size; +pub(crate) mod unproject; + use context::KayakRootContext; pub use window_size::WindowSize; diff --git a/src/unproject.rs b/src/unproject.rs new file mode 100644 index 0000000000000000000000000000000000000000..dff2687f6422436bd1a9846f9ecc3c1056fccaf5 --- /dev/null +++ b/src/unproject.rs @@ -0,0 +1,47 @@ +use bevy::ecs::system::SystemParam; +use bevy::math::Vec2; +use bevy::prelude::{OrthographicProjection, Query, Vec4Swizzles, Window, With}; +use bevy::utils::thiserror::Error; +use bevy::window::PrimaryWindow; +use crate::CameraUIKayak; + +pub fn unproject_from_physical( + point: Vec2, + window: &Window, + projection: &OrthographicProjection, +) -> Vec2 { + let projection_area = projection.area; + let projection_width = projection_area.width(); + let projection_height = projection_area.height(); + + let window_width = window.width(); + let window_height = window.height(); + + let width_ratio = projection_width / window_width; + let height_ratio = projection_height / window_height; + + point * Vec2::new(width_ratio, height_ratio) +} + +#[derive(SystemParam)] +pub struct UnprojectManager<'w, 's> { + windows: Query<'w, 's, &'static Window, With<PrimaryWindow>>, + camera: Query<'w, 's, &'static OrthographicProjection, With<CameraUIKayak>>, +} + +#[derive(Debug, Error)] +#[error("Invalid ECS state to perform unprojection")] +pub struct InvalidUnprojection; + +impl<'w, 's> UnprojectManager<'w, 's> { + pub fn unproject(&self, position: Vec2) -> Result<Vec2, InvalidUnprojection> { + let window = self.windows.get_single().map_err(|_| InvalidUnprojection)?; + let camera = self.camera.get_single().map_err(|_| InvalidUnprojection)?; + + Ok(unproject_from_physical( + position, + window, + camera, + )) + } +}