Skip to content

Commit

Permalink
fix: upgrade to winit v0.30 (bevyengine#13366)
Browse files Browse the repository at this point in the history
- Upgrade winit to v0.30
- Fixes bevyengine#13331

This is a rewrite/adaptation of the new trait system described and
implemented in `winit` v0.30.

The custom UserEvent is now renamed as WakeUp, used to wake up the loop
if anything happens outside the app (a new
[custom_user_event](https://github.com/bevyengine/bevy/pull/13366/files#diff-2de8c0a8d3028d0059a3d80ae31b2bbc1cde2595ce2d317ea378fe3e0cf6ef2d)
shows this behavior.

The internal `UpdateState` has been removed and replaced internally by
the AppLifecycle. When changed, the AppLifecycle is sent as an event.

The `UpdateMode` now accepts only two values: `Continuous` and
`Reactive`, but the latter exposes 3 new properties to enable reactive
to device, user or window events. The previous `UpdateMode::Reactive` is
now equivalent to `UpdateMode::reactive()`, while
`UpdateMode::ReactiveLowPower` to `UpdateMode::reactive_low_power()`.

The `ApplicationLifecycle` has been renamed as `AppLifecycle`, and now
contains the possible values of the application state inside the event
loop:
* `Idle`: the loop has not started yet
* `Running` (previously called `Started`): the loop is running
* `WillSuspend`: the loop is going to be suspended
* `Suspended`: the loop is suspended
* `WillResume`: the loop is going to be resumed

Note: the `Resumed` state has been removed since the resumed app is just
running.

Finally, now that `winit` enables this, it extends the `WinitPlugin` to
support custom events.

- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGPU
- [x] WASM/WebGL2

- [ ] iOS: build failed in CI
   - blocking, but may just be flakiness
- [x] Cross-platform: when the window is maximised, changes in the scale
factor don't apply, to make them apply one has to make the window
smaller again. (Re-maximising keeps the updated scale factor)
    - non-blocking, but good to fix
- [ ] Android: it's pretty easy to quickly open and close the app and
then the music keeps playing when suspended.
    - non-blocking but worrying
- [ ]  Web: the application will hang when switching tabs
- Not new, duplicate of bevyengine#13486
- [ ] Cross-platform?: Screenshot failure, `ERROR present_frames:
wgpu_core::present: No work has been submitted for this frame before`
taking the first screenshot, but after pressing space
    - non-blocking, but good to fix

---------

Co-authored-by: François <francois.mockers@vleue.com>
  • Loading branch information
2 people authored and knutsoned committed Jun 25, 2024
1 parent f677f40 commit 44b9719
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 267 deletions.
102 changes: 47 additions & 55 deletions crates/bevy_window/src/window.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use std::num::NonZeroU32;

use bevy_ecs::{
entity::{Entity, EntityMapper, MapEntities},
prelude::{Component, ReflectComponent},
entity::{ Entity, EntityMapper, MapEntities },
prelude::{ Component, ReflectComponent },
};
use bevy_math::{DVec2, IVec2, UVec2, Vec2};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_math::{ DVec2, IVec2, UVec2, Vec2 };
use bevy_reflect::{ std_traits::ReflectDefault, Reflect };

#[cfg(feature = "serialize")]
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
use bevy_reflect::{ ReflectDeserialize, ReflectSerialize };

use bevy_utils::tracing::warn;

Expand Down Expand Up @@ -67,7 +67,7 @@ impl MapEntities for WindowRef {
*entity = entity_mapper.map_entity(*entity);
}
Self::Primary => {}
};
}
}
}

Expand Down Expand Up @@ -424,8 +424,9 @@ impl Window {
/// See [`WindowResolution`] for an explanation about logical/physical sizes.
#[inline]
pub fn cursor_position(&self) -> Option<Vec2> {
self.physical_cursor_position()
.map(|position| (position.as_dvec2() / self.scale_factor() as f64).as_vec2())
self.physical_cursor_position().map(|position|
(position.as_dvec2() / (self.scale_factor() as f64)).as_vec2()
)
}

/// The cursor position in this window in physical pixels.
Expand All @@ -437,10 +438,11 @@ impl Window {
pub fn physical_cursor_position(&self) -> Option<Vec2> {
match self.internal.physical_cursor_position {
Some(position) => {
if position.x >= 0.
&& position.y >= 0.
&& position.x < self.physical_width() as f64
&& position.y < self.physical_height() as f64
if
position.x >= 0.0 &&
position.y >= 0.0 &&
position.x < (self.physical_width() as f64) &&
position.y < (self.physical_height() as f64)
{
Some(position.as_vec2())
} else {
Expand All @@ -455,8 +457,9 @@ impl Window {
///
/// See [`WindowResolution`] for an explanation about logical/physical sizes.
pub fn set_cursor_position(&mut self, position: Option<Vec2>) {
self.internal.physical_cursor_position =
position.map(|p| p.as_dvec2() * self.scale_factor() as f64);
self.internal.physical_cursor_position = position.map(
|p| p.as_dvec2() * (self.scale_factor() as f64)
);
}

/// Set the cursor position in this window in physical pixels.
Expand Down Expand Up @@ -496,8 +499,8 @@ pub struct WindowResizeConstraints {
impl Default for WindowResizeConstraints {
fn default() -> Self {
Self {
min_width: 180.,
min_height: 120.,
min_width: 180.0,
min_height: 120.0,
max_width: f32::INFINITY,
max_height: f32::INFINITY,
}
Expand All @@ -516,19 +519,21 @@ impl WindowResizeConstraints {
mut max_width,
mut max_height,
} = self;
min_width = min_width.max(1.);
min_height = min_height.max(1.);
min_width = min_width.max(1.0);
min_height = min_height.max(1.0);
if max_width < min_width {
warn!(
"The given maximum width {} is smaller than the minimum width {}",
max_width, min_width
max_width,
min_width
);
max_width = min_width;
}
if max_height < min_height {
warn!(
"The given maximum height {} is smaller than the minimum height {}",
max_height, min_height
max_height,
min_height
);
max_height = min_height;
}
Expand Down Expand Up @@ -735,13 +740,13 @@ impl WindowResolution {
/// The window's client area width in logical pixels.
#[inline]
pub fn width(&self) -> f32 {
self.physical_width() as f32 / self.scale_factor()
(self.physical_width() as f32) / self.scale_factor()
}

/// The window's client area height in logical pixels.
#[inline]
pub fn height(&self) -> f32 {
self.physical_height() as f32 / self.scale_factor()
(self.physical_height() as f32) / self.scale_factor()
}

/// The window's client size in logical pixels
Expand Down Expand Up @@ -772,8 +777,7 @@ impl WindowResolution {
///
/// `physical_pixels = logical_pixels * scale_factor`
pub fn scale_factor(&self) -> f32 {
self.scale_factor_override
.unwrap_or_else(|| self.base_scale_factor())
self.scale_factor_override.unwrap_or_else(|| self.base_scale_factor())
}

/// The window scale factor as reported by the window backend.
Expand All @@ -797,7 +801,7 @@ impl WindowResolution {
pub fn set(&mut self, width: f32, height: f32) {
self.set_physical_resolution(
(width * self.scale_factor()) as u32,
(height * self.scale_factor()) as u32,
(height * self.scale_factor()) as u32
);
}

Expand Down Expand Up @@ -825,8 +829,8 @@ impl WindowResolution {
#[doc(hidden)]
pub fn set_scale_factor_and_apply_to_physical_size(&mut self, scale_factor: f32) {
self.scale_factor = scale_factor;
self.physical_width = (self.physical_width as f32 * scale_factor) as u32;
self.physical_height = (self.physical_height as f32 * scale_factor) as u32;
self.physical_width = ((self.physical_width as f32) * scale_factor) as u32;
self.physical_height = ((self.physical_height as f32) * scale_factor) as u32;
}

/// Set the window's scale factor, this will be used over what the backend decides.
Expand All @@ -839,19 +843,13 @@ impl WindowResolution {
}
}

impl<I> From<(I, I)> for WindowResolution
where
I: Into<f32>,
{
impl<I> From<(I, I)> for WindowResolution where I: Into<f32> {
fn from((width, height): (I, I)) -> WindowResolution {
WindowResolution::new(width.into(), height.into())
}
}

impl<I> From<[I; 2]> for WindowResolution
where
I: Into<f32>,
{
impl<I> From<[I; 2]> for WindowResolution where I: Into<f32> {
fn from([width, height]: [I; 2]) -> WindowResolution {
WindowResolution::new(width.into(), height.into())
}
Expand Down Expand Up @@ -1224,48 +1222,42 @@ mod tests {
#[test]
fn cursor_position_within_window_bounds() {
let mut window = Window {
resolution: WindowResolution::new(800., 600.),
resolution: WindowResolution::new(800.0, 600.0),
..Default::default()
};

window.set_physical_cursor_position(Some(DVec2::new(0., 300.)));
assert_eq!(window.physical_cursor_position(), Some(Vec2::new(0., 300.)));
window.set_physical_cursor_position(Some(DVec2::new(0.0, 300.0)));
assert_eq!(window.physical_cursor_position(), Some(Vec2::new(0.0, 300.0)));

window.set_physical_cursor_position(Some(DVec2::new(400., 0.)));
assert_eq!(window.physical_cursor_position(), Some(Vec2::new(400., 0.)));
window.set_physical_cursor_position(Some(DVec2::new(400.0, 0.0)));
assert_eq!(window.physical_cursor_position(), Some(Vec2::new(400.0, 0.0)));

window.set_physical_cursor_position(Some(DVec2::new(799.999, 300.)));
assert_eq!(
window.physical_cursor_position(),
Some(Vec2::new(799.999, 300.)),
);
window.set_physical_cursor_position(Some(DVec2::new(799.999, 300.0)));
assert_eq!(window.physical_cursor_position(), Some(Vec2::new(799.999, 300.0)));

window.set_physical_cursor_position(Some(DVec2::new(400., 599.999)));
assert_eq!(
window.physical_cursor_position(),
Some(Vec2::new(400., 599.999))
);
window.set_physical_cursor_position(Some(DVec2::new(400.0, 599.999)));
assert_eq!(window.physical_cursor_position(), Some(Vec2::new(400.0, 599.999)));
}

// Checks that `Window::physical_cursor_position` returns `None` if the cursor position is not
// within the bounds of the window.
#[test]
fn cursor_position_not_within_window_bounds() {
let mut window = Window {
resolution: WindowResolution::new(800., 600.),
resolution: WindowResolution::new(800.0, 600.0),
..Default::default()
};

window.set_physical_cursor_position(Some(DVec2::new(-0.001, 300.)));
window.set_physical_cursor_position(Some(DVec2::new(-0.001, 300.0)));
assert!(window.physical_cursor_position().is_none());

window.set_physical_cursor_position(Some(DVec2::new(400., -0.001)));
window.set_physical_cursor_position(Some(DVec2::new(400.0, -0.001)));
assert!(window.physical_cursor_position().is_none());

window.set_physical_cursor_position(Some(DVec2::new(800., 300.)));
window.set_physical_cursor_position(Some(DVec2::new(800.0, 300.0)));
assert!(window.physical_cursor_position().is_none());

window.set_physical_cursor_position(Some(DVec2::new(400., 600.)));
window.set_physical_cursor_position(Some(DVec2::new(400.0, 600.0)));
assert!(window.physical_cursor_position().is_none());
}
}
Loading

0 comments on commit 44b9719

Please sign in to comment.