Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions crates/bevy_camera_controller/src/free_camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use bevy_camera::Camera;
use bevy_ecs::prelude::*;
use bevy_input::keyboard::KeyCode;
use bevy_input::mouse::{
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseScrollUnit,
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseScrollPixelsPerLine,
};
use bevy_input::touch::Touches;
use bevy_input::ButtonInput;
Expand Down Expand Up @@ -267,6 +267,7 @@ pub fn run_freecamera_controller(
mut windows: Query<(&Window, &mut CursorOptions)>,
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
accumulated_mouse_scroll: Res<AccumulatedMouseScroll>,
mouse_scroll_conversion: Res<MouseScrollPixelsPerLine>,
touch_input: Res<Touches>,
mouse_button_input: Res<ButtonInput<MouseButton>>,
key_input: Res<ButtonInput<KeyCode>>,
Expand Down Expand Up @@ -302,12 +303,10 @@ pub fn run_freecamera_controller(
return;
}

let scroll = match accumulated_mouse_scroll.unit {
MouseScrollUnit::Line => accumulated_mouse_scroll.delta.y,
MouseScrollUnit::Pixel => {
accumulated_mouse_scroll.delta.y / MouseScrollUnit::SCROLL_UNIT_CONVERSION_FACTOR
}
};
let scroll = accumulated_mouse_scroll
.to_lines(&mouse_scroll_conversion)
.delta
.y;
// By using exponentiation we ensure that this scales up and down smoothly
// regardless of the amount of scrolling processed per frame
state.speed_multiplier *= exp(config.scroll_factor * scroll);
Expand Down
13 changes: 6 additions & 7 deletions crates/bevy_camera_controller/src/pan_camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy_app::{App, Plugin, RunFixedMainLoop, RunFixedMainLoopSystems};
use bevy_camera::{Camera, RenderTarget};
use bevy_ecs::prelude::*;
use bevy_input::keyboard::KeyCode;
use bevy_input::mouse::{AccumulatedMouseScroll, MouseButton, MouseScrollUnit};
use bevy_input::mouse::{AccumulatedMouseScroll, MouseButton, MouseScrollPixelsPerLine};
use bevy_input::ButtonInput;
use bevy_math::{Vec2, Vec3};
use bevy_picking::events::{Drag, DragEnd, DragStart, Pointer};
Expand Down Expand Up @@ -167,6 +167,7 @@ fn run_pancamera_controller(
time: Res<Time<Real>>,
key_input: Res<ButtonInput<KeyCode>>,
accumulated_mouse_scroll: Res<AccumulatedMouseScroll>,
mouse_scroll_conversion: Res<MouseScrollPixelsPerLine>,
mut query: Query<(&mut Transform, &mut PanCamera), With<Camera>>,
) {
let dt = time.delta_secs();
Expand Down Expand Up @@ -240,12 +241,10 @@ fn run_pancamera_controller(
}

// (with mouse wheel)
let mouse_scroll = match accumulated_mouse_scroll.unit {
MouseScrollUnit::Line => accumulated_mouse_scroll.delta.y,
MouseScrollUnit::Pixel => {
accumulated_mouse_scroll.delta.y / MouseScrollUnit::SCROLL_UNIT_CONVERSION_FACTOR
}
};
let mouse_scroll = accumulated_mouse_scroll
.to_lines(&mouse_scroll_conversion)
.delta
.y;
zoom_amount += mouse_scroll * controller.zoom_speed;

controller.zoom_factor =
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ use keyboard::{keyboard_input_system, Key, KeyCode, KeyboardFocusLost, KeyboardI
use mouse::{
accumulate_mouse_motion_system, accumulate_mouse_scroll_system, mouse_button_input_system,
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseButtonInput, MouseMotion,
MouseWheel,
MouseScrollPixelsPerLine, MouseWheel,
};

#[cfg(feature = "touch")]
Expand Down Expand Up @@ -122,6 +122,7 @@ impl Plugin for InputPlugin {
.add_message::<MouseWheel>()
.init_resource::<AccumulatedMouseMotion>()
.init_resource::<AccumulatedMouseScroll>()
.init_resource::<MouseScrollPixelsPerLine>()
.init_resource::<ButtonInput<MouseButton>>()
.add_systems(
PreUpdate,
Expand Down
84 changes: 74 additions & 10 deletions crates/bevy_input/src/mouse.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! The mouse input functionality.

use core::ops::{Div, Mul};

use crate::{touch::TouchPhase, ButtonInput, ButtonState};
#[cfg(feature = "bevy_reflect")]
use bevy_ecs::prelude::ReflectMessage;
Expand All @@ -11,6 +13,8 @@ use bevy_ecs::{
system::ResMut,
};
use bevy_math::Vec2;
use derive_more::{Deref, DerefMut};

#[cfg(feature = "bevy_reflect")]
use {
bevy_ecs::reflect::ReflectResource,
Expand Down Expand Up @@ -139,18 +143,53 @@ pub enum MouseScrollUnit {
Pixel,
}

impl MouseScrollUnit {
/// An approximate conversion factor to account for the difference between
/// [`MouseScrollUnit::Line`] and [`MouseScrollUnit::Pixel`].
///
/// Each line corresponds to many pixels; this must be corrected for in order to ensure that
/// mouse wheel controls are scaled properly regardless of the provided input events for the end user.
///
/// This value is correct for Microsoft Edge, but its validity has not been broadly tested.
/// Please file an issue if you find that this differs on certain platforms or hardware!
pub const SCROLL_UNIT_CONVERSION_FACTOR: f32 = 100.;
/// Describes the quantity of [`MouseScrollUnit::Pixel`]s per [`MouseScrollUnit::Line`]
#[derive(Debug, Clone, Copy, PartialEq, Resource, Deref, DerefMut)]
#[cfg_attr(
feature = "bevy_reflect",
derive(Reflect),
reflect(Debug, PartialEq, Clone)
)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
all(feature = "serialize", feature = "bevy_reflect"),
reflect(Serialize, Deserialize)
)]
pub struct MouseScrollPixelsPerLine(f32);

impl Default for MouseScrollPixelsPerLine {
fn default() -> Self {
MouseScrollPixelsPerLine(100.0)
}
}

impl Mul<MouseScrollPixelsPerLine> for f32 {
type Output = f32;
fn mul(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
self * rhs.0
}
}

impl Div<MouseScrollPixelsPerLine> for f32 {
type Output = f32;
fn div(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
self / rhs.0
}
}

impl Mul<MouseScrollPixelsPerLine> for Vec2 {
type Output = Vec2;
fn mul(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
self * rhs.0
}
}

impl Div<MouseScrollPixelsPerLine> for Vec2 {
type Output = Vec2;
fn div(self, rhs: MouseScrollPixelsPerLine) -> Self::Output {
self / rhs.0
}
}
/// A mouse wheel event.
///
/// This event is the translated version of the `WindowEvent::MouseWheel` from the `winit` crate.
Expand Down Expand Up @@ -254,6 +293,31 @@ impl Default for AccumulatedMouseScroll {
}
}

impl AccumulatedMouseScroll {
/// Converts the units to [`MouseScrollUnit::Line`]
pub fn to_lines(&self, conversion_ratio: &MouseScrollPixelsPerLine) -> Self {
if self.unit == MouseScrollUnit::Pixel {
AccumulatedMouseScroll {
unit: MouseScrollUnit::Line,
delta: self.delta / *conversion_ratio,
}
} else {
*self
}
}
/// Converts the units to [`MouseScrollUnit::Pixel`]
pub fn to_pixels(&self, conversion_ratio: &MouseScrollPixelsPerLine) -> Self {
if self.unit == MouseScrollUnit::Line {
AccumulatedMouseScroll {
unit: MouseScrollUnit::Pixel,
delta: self.delta * *conversion_ratio,
}
} else {
*self
}
}
}

/// Updates the [`AccumulatedMouseMotion`] resource using the [`MouseMotion`] event.
/// The value of [`AccumulatedMouseMotion`] is reset to zero every frame
pub fn accumulate_mouse_motion_system(
Expand Down
11 changes: 4 additions & 7 deletions examples/camera/projection_zoom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
use std::{f32::consts::PI, ops::Range};

use bevy::{
camera::ScalingMode, input::mouse::AccumulatedMouseScroll, input::mouse::MouseScrollUnit,
camera::ScalingMode,
input::mouse::{AccumulatedMouseScroll, MouseScrollPixelsPerLine},
prelude::*,
};

Expand Down Expand Up @@ -138,17 +139,13 @@ fn zoom(
camera: Single<&mut Projection, With<Camera>>,
camera_settings: Res<CameraSettings>,
mouse_wheel_input: Res<AccumulatedMouseScroll>,
scroll_conversion: Res<MouseScrollPixelsPerLine>,
) {
// Usually, you won't need to handle both types of projection,
// but doing so makes for a more complete example.

// Get a scroll amount proportional to the kind of input that generated it.
let scroll = match mouse_wheel_input.unit {
MouseScrollUnit::Line => mouse_wheel_input.delta.y,
MouseScrollUnit::Pixel => {
mouse_wheel_input.delta.y / MouseScrollUnit::SCROLL_UNIT_CONVERSION_FACTOR
}
};
let scroll = mouse_wheel_input.to_lines(&scroll_conversion).delta.y;

match *camera.into_inner() {
Projection::Orthographic(ref mut orthographic) => {
Expand Down
Loading