update Window's width & height methods to return f32 (#1033)

update `Window`'s `width` & `height` methods to return `f32`
This commit is contained in:
Nathan Jeffords 2020-12-13 15:05:56 -08:00 committed by GitHub
parent e511cdbda7
commit d2e4327b14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 144 additions and 93 deletions

View file

@ -78,7 +78,7 @@ pub fn camera_system<T: CameraProjection + Component>(
for (entity, mut camera, mut camera_projection) in queries.q0_mut().iter_mut() { for (entity, mut camera, mut camera_projection) in queries.q0_mut().iter_mut() {
if let Some(window) = windows.get(camera.window) { if let Some(window) = windows.get(camera.window) {
if changed_window_ids.contains(&window.id()) || added_cameras.contains(&entity) { if changed_window_ids.contains(&window.id()) || added_cameras.contains(&entity) {
camera_projection.update(window.logical_width(), window.logical_height()); camera_projection.update(window.width(), window.height());
camera.projection_matrix = camera_projection.get_projection_matrix(); camera.projection_matrix = camera_projection.get_projection_matrix();
camera.depth_calculation = camera_projection.depth_calculation(); camera.depth_calculation = camera_projection.depth_calculation();
} }

View file

@ -116,8 +116,8 @@ impl FlexSurface {
*node, *node,
stretch::style::Style { stretch::style::Style {
size: stretch::geometry::Size { size: stretch::geometry::Size {
width: stretch::style::Dimension::Points(window.logical_width()), width: stretch::style::Dimension::Points(window.width()),
height: stretch::style::Dimension::Points(window.logical_height()), height: stretch::style::Dimension::Points(window.height()),
}, },
..Default::default() ..Default::default()
}, },

View file

@ -32,11 +32,29 @@ impl Default for WindowId {
} }
} }
/// An operating system window that can present content and receive user input.
///
/// ## Window Sizes
///
/// There are three sizes associated with a window. The physical size which is
/// the height and width in physical pixels on the monitor. The logical size
/// which is the physical size scaled by an operating system provided factor to
/// account for monitors with differing pixel densities or user preference. And
/// the requested size, measured in logical pixels, which is the value submitted
/// to the API when creating the window, or requesting that it be resized.
///
/// The actual size, in logical pixels, of the window may not match the
/// requested size due to operating system limits on the window size, or the
/// quantization of the logical size when converting the physical size to the
/// logical size through the scaling factor.
#[derive(Debug)] #[derive(Debug)]
pub struct Window { pub struct Window {
id: WindowId, id: WindowId,
requested_width: f32,
requested_height: f32,
physical_width: u32, physical_width: u32,
physical_height: u32, physical_height: u32,
scale_factor: f64,
title: String, title: String,
vsync: bool, vsync: bool,
resizable: bool, resizable: bool,
@ -48,7 +66,6 @@ pub struct Window {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
pub canvas: Option<String>, pub canvas: Option<String>,
command_queue: Vec<WindowCommand>, command_queue: Vec<WindowCommand>,
scale_factor: f64,
} }
#[derive(Debug)] #[derive(Debug)]
@ -61,8 +78,7 @@ pub enum WindowCommand {
title: String, title: String,
}, },
SetResolution { SetResolution {
physical_width: u32, resolution: (f32, f32),
physical_height: u32,
}, },
SetVsync { SetVsync {
vsync: bool, vsync: bool,
@ -100,11 +116,20 @@ pub enum WindowMode {
} }
impl Window { impl Window {
pub fn new(id: WindowId, window_descriptor: &WindowDescriptor) -> Self { pub fn new(
id: WindowId,
window_descriptor: &WindowDescriptor,
physical_width: u32,
physical_height: u32,
scale_factor: f64,
) -> Self {
Window { Window {
id, id,
physical_height: window_descriptor.height, requested_width: window_descriptor.width,
physical_width: window_descriptor.width, requested_height: window_descriptor.height,
physical_width,
physical_height,
scale_factor,
title: window_descriptor.title.clone(), title: window_descriptor.title.clone(),
vsync: window_descriptor.vsync, vsync: window_descriptor.vsync,
resizable: window_descriptor.resizable, resizable: window_descriptor.resizable,
@ -116,7 +141,6 @@ impl Window {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
canvas: window_descriptor.canvas.clone(), canvas: window_descriptor.canvas.clone(),
command_queue: Vec::new(), command_queue: Vec::new(),
scale_factor: 1.0,
} }
} }
@ -125,31 +149,45 @@ impl Window {
self.id self.id
} }
/// The current logical width of the window's client area.
#[inline] #[inline]
pub fn width(&self) -> u32 { pub fn width(&self) -> f32 {
self.logical_width() as u32
}
#[inline]
pub fn height(&self) -> u32 {
self.logical_height() as u32
}
#[inline]
pub fn logical_width(&self) -> f32 {
(self.physical_width as f64 / self.scale_factor) as f32 (self.physical_width as f64 / self.scale_factor) as f32
} }
/// The current logical height of the window's client area.
#[inline] #[inline]
pub fn logical_height(&self) -> f32 { pub fn height(&self) -> f32 {
(self.physical_height as f64 / self.scale_factor) as f32 (self.physical_height as f64 / self.scale_factor) as f32
} }
/// The requested window client area width in logical pixels from window
/// creation or the last call to [set_resolution](Window::set_resolution).
///
/// This may differ from the actual width depending on OS size limits and
/// the scaling factor for high DPI monitors.
#[inline]
pub fn requested_width(&self) -> f32 {
self.requested_width
}
/// The requested window client area height in logical pixels from window
/// creation or the last call to [set_resolution](Window::set_resolution).
///
/// This may differ from the actual width depending on OS size limits and
/// the scaling factor for high DPI monitors.
#[inline]
pub fn requested_height(&self) -> f32 {
self.requested_height
}
/// The window's client area width in physical pixels.
#[inline] #[inline]
pub fn physical_width(&self) -> u32 { pub fn physical_width(&self) -> u32 {
self.physical_width self.physical_width
} }
/// The window's client area height in physical pixels.
#[inline] #[inline]
pub fn physical_height(&self) -> u32 { pub fn physical_height(&self) -> u32 {
self.physical_height self.physical_height
@ -161,28 +199,32 @@ impl Window {
.push(WindowCommand::SetMaximized { maximized }); .push(WindowCommand::SetMaximized { maximized });
} }
pub fn set_resolution(&mut self, width: u32, height: u32) { /// Request the OS to resize the window such the the client area matches the
self.physical_width = (width as f64 * self.scale_factor) as u32; /// specified width and height.
self.physical_height = (height as f64 * self.scale_factor) as u32; pub fn set_resolution(&mut self, width: f32, height: f32) {
self.requested_width = width;
self.requested_height = height;
self.command_queue.push(WindowCommand::SetResolution { self.command_queue.push(WindowCommand::SetResolution {
physical_width: self.physical_width, resolution: (self.requested_width, self.requested_height),
physical_height: self.physical_height,
}); });
} }
#[allow(missing_docs)]
#[inline]
pub fn update_physical_size_from_backend(&mut self, width: u32, height: u32) {
self.physical_width = width;
self.physical_height = height;
}
#[allow(missing_docs)] #[allow(missing_docs)]
#[inline] #[inline]
pub fn update_scale_factor_from_backend(&mut self, scale_factor: f64) { pub fn update_scale_factor_from_backend(&mut self, scale_factor: f64) {
self.scale_factor = scale_factor; self.scale_factor = scale_factor;
} }
#[allow(missing_docs)]
#[inline]
pub fn update_actual_size_from_backend(&mut self, physical_width: u32, physical_height: u32) {
self.physical_width = physical_width;
self.physical_height = physical_height;
}
/// The ratio of physical pixels to logical pixels
///
/// `physical_pixels = logical_pixels * scale_factor`
#[inline] #[inline]
pub fn scale_factor(&self) -> f64 { pub fn scale_factor(&self) -> f64 {
self.scale_factor self.scale_factor
@ -291,8 +333,8 @@ impl Window {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct WindowDescriptor { pub struct WindowDescriptor {
pub width: u32, pub width: f32,
pub height: u32, pub height: f32,
pub title: String, pub title: String,
pub vsync: bool, pub vsync: bool,
pub resizable: bool, pub resizable: bool,
@ -308,8 +350,8 @@ impl Default for WindowDescriptor {
fn default() -> Self { fn default() -> Self {
WindowDescriptor { WindowDescriptor {
title: "bevy".to_string(), title: "bevy".to_string(),
width: 1280, width: 1280.,
height: 720, height: 720.,
vsync: true, vsync: true,
resizable: true, resizable: true,
decorations: true, decorations: true,

View file

@ -14,8 +14,8 @@ use bevy_ecs::{Resources, World};
use bevy_math::Vec2; use bevy_math::Vec2;
use bevy_utils::tracing::{error, trace}; use bevy_utils::tracing::{error, trace};
use bevy_window::{ use bevy_window::{
CreateWindow, CursorEntered, CursorLeft, CursorMoved, ReceivedCharacter, Window, CreateWindow, CursorEntered, CursorLeft, CursorMoved, ReceivedCharacter, WindowCloseRequested,
WindowCloseRequested, WindowCreated, WindowFocused, WindowResized, Windows, WindowCreated, WindowFocused, WindowResized, Windows,
}; };
use winit::{ use winit::{
event::{self, DeviceEvent, Event, WindowEvent}, event::{self, DeviceEvent, Event, WindowEvent},
@ -68,13 +68,12 @@ fn change_window(_: &mut World, resources: &mut Resources) {
window.set_title(&title); window.set_title(&title);
} }
bevy_window::WindowCommand::SetResolution { bevy_window::WindowCommand::SetResolution {
physical_width, resolution: (logical_width, logical_height),
physical_height,
} => { } => {
let window = winit_windows.get_window(id).unwrap(); let window = winit_windows.get_window(id).unwrap();
window.set_inner_size(winit::dpi::PhysicalSize::new( window.set_inner_size(winit::dpi::LogicalSize::new(
physical_width, logical_width,
physical_height, logical_height,
)); ));
} }
bevy_window::WindowCommand::SetVsync { .. } => (), bevy_window::WindowCommand::SetVsync { .. } => (),
@ -194,14 +193,13 @@ pub fn winit_runner(mut app: App) {
let mut windows = app.resources.get_mut::<Windows>().unwrap(); let mut windows = app.resources.get_mut::<Windows>().unwrap();
let window_id = winit_windows.get_window_id(winit_window_id).unwrap(); let window_id = winit_windows.get_window_id(winit_window_id).unwrap();
let window = windows.get_mut(window_id).unwrap(); let window = windows.get_mut(window_id).unwrap();
window.update_physical_size_from_backend(size.width, size.height); window.update_actual_size_from_backend(size.width, size.height);
let mut resize_events = let mut resize_events =
app.resources.get_mut::<Events<WindowResized>>().unwrap(); app.resources.get_mut::<Events<WindowResized>>().unwrap();
resize_events.send(WindowResized { resize_events.send(WindowResized {
id: window_id, id: window_id,
height: window.logical_height(), width: window.width(),
width: window.logical_width(), height: window.height(),
}); });
} }
WindowEvent::CloseRequested => { WindowEvent::CloseRequested => {
@ -299,7 +297,7 @@ pub fn winit_runner(mut app: App) {
// FIXME?: On Android window start is top while on PC/Linux/OSX on bottom // FIXME?: On Android window start is top while on PC/Linux/OSX on bottom
if cfg!(target_os = "android") { if cfg!(target_os = "android") {
let window_height = windows.get_primary().unwrap().logical_height(); let window_height = windows.get_primary().unwrap().height();
location.y = window_height - location.y; location.y = window_height - location.y;
} }
touch_input_events.send(converters::convert_touch_input(touch, location)); touch_input_events.send(converters::convert_touch_input(touch, location));
@ -326,11 +324,13 @@ pub fn winit_runner(mut app: App) {
let mut windows = app.resources.get_mut::<Windows>().unwrap(); let mut windows = app.resources.get_mut::<Windows>().unwrap();
let window_id = winit_windows.get_window_id(winit_window_id).unwrap(); let window_id = winit_windows.get_window_id(winit_window_id).unwrap();
let window = windows.get_mut(window_id).unwrap(); let window = windows.get_mut(window_id).unwrap();
window.update_physical_size_from_backend( window.update_actual_size_from_backend(
new_inner_size.width, new_inner_size.width,
new_inner_size.height, new_inner_size.height,
); );
window.update_scale_factor_from_backend(scale_factor); window.update_scale_factor_from_backend(scale_factor);
// should we send a resize event to indicate the change in
// logical size?
} }
WindowEvent::Focused(focused) => { WindowEvent::Focused(focused) => {
let mut focused_events = let mut focused_events =
@ -382,10 +382,14 @@ fn handle_create_window_events(
let create_window_events = resources.get::<Events<CreateWindow>>().unwrap(); let create_window_events = resources.get::<Events<CreateWindow>>().unwrap();
let mut window_created_events = resources.get_mut::<Events<WindowCreated>>().unwrap(); let mut window_created_events = resources.get_mut::<Events<WindowCreated>>().unwrap();
for create_window_event in create_window_event_reader.iter(&create_window_events) { for create_window_event in create_window_event_reader.iter(&create_window_events) {
let mut window = Window::new(create_window_event.id, &create_window_event.descriptor); let window = winit_windows.create_window(
winit_windows.create_window(event_loop, &mut window); event_loop,
let window_id = window.id(); create_window_event.id,
&create_window_event.descriptor,
);
windows.add(window); windows.add(window);
window_created_events.send(WindowCreated { id: window_id }); window_created_events.send(WindowCreated {
id: create_window_event.id,
});
} }
} }

View file

@ -1,5 +1,5 @@
use bevy_utils::HashMap; use bevy_utils::HashMap;
use bevy_window::{Window, WindowId, WindowMode}; use bevy_window::{Window, WindowDescriptor, WindowId, WindowMode};
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct WinitWindows { pub struct WinitWindows {
@ -12,8 +12,9 @@ impl WinitWindows {
pub fn create_window( pub fn create_window(
&mut self, &mut self,
event_loop: &winit::event_loop::EventLoopWindowTarget<()>, event_loop: &winit::event_loop::EventLoopWindowTarget<()>,
window: &mut Window, window_id: WindowId,
) { window_descriptor: &WindowDescriptor,
) -> Window {
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
let mut winit_window_builder = { let mut winit_window_builder = {
use winit::platform::windows::WindowBuilderExtWindows; use winit::platform::windows::WindowBuilderExtWindows;
@ -23,7 +24,7 @@ impl WinitWindows {
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
let mut winit_window_builder = winit::window::WindowBuilder::new(); let mut winit_window_builder = winit::window::WindowBuilder::new();
winit_window_builder = match window.mode() { winit_window_builder = match window_descriptor.mode {
WindowMode::BorderlessFullscreen => winit_window_builder.with_fullscreen(Some( WindowMode::BorderlessFullscreen => winit_window_builder.with_fullscreen(Some(
winit::window::Fullscreen::Borderless(event_loop.primary_monitor()), winit::window::Fullscreen::Borderless(event_loop.primary_monitor()),
)), )),
@ -31,30 +32,30 @@ impl WinitWindows {
winit::window::Fullscreen::Exclusive(match use_size { winit::window::Fullscreen::Exclusive(match use_size {
true => get_fitting_videomode( true => get_fitting_videomode(
&event_loop.primary_monitor().unwrap(), &event_loop.primary_monitor().unwrap(),
window.physical_width(), window_descriptor.width as u32,
window.physical_height(), window_descriptor.height as u32,
), ),
false => get_best_videomode(&event_loop.primary_monitor().unwrap()), false => get_best_videomode(&event_loop.primary_monitor().unwrap()),
}), }),
)), )),
_ => winit_window_builder _ => winit_window_builder
.with_inner_size(winit::dpi::LogicalSize::new( .with_inner_size(winit::dpi::LogicalSize::new(
window.width(), window_descriptor.width,
window.height(), window_descriptor.height,
)) ))
.with_resizable(window.resizable()) .with_resizable(window_descriptor.resizable)
.with_decorations(window.decorations()), .with_decorations(window_descriptor.decorations),
}; };
#[allow(unused_mut)] #[allow(unused_mut)]
let mut winit_window_builder = winit_window_builder.with_title(window.title()); let mut winit_window_builder = winit_window_builder.with_title(&window_descriptor.title);
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
{ {
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use winit::platform::web::WindowBuilderExtWebSys; use winit::platform::web::WindowBuilderExtWebSys;
if let Some(selector) = &window.canvas { if let Some(selector) = &window_descriptor.canvas {
let window = web_sys::window().unwrap(); let window = web_sys::window().unwrap();
let document = window.document().unwrap(); let document = window.document().unwrap();
let canvas = document let canvas = document
@ -71,24 +72,22 @@ impl WinitWindows {
let winit_window = winit_window_builder.build(&event_loop).unwrap(); let winit_window = winit_window_builder.build(&event_loop).unwrap();
match winit_window.set_cursor_grab(window.cursor_locked()) { match winit_window.set_cursor_grab(window_descriptor.cursor_locked) {
Ok(_) => {} Ok(_) => {}
Err(winit::error::ExternalError::NotSupported(_)) => {} Err(winit::error::ExternalError::NotSupported(_)) => {}
Err(err) => Err(err).unwrap(), Err(err) => Err(err).unwrap(),
} }
winit_window.set_cursor_visible(window.cursor_visible()); winit_window.set_cursor_visible(window_descriptor.cursor_visible);
self.window_id_to_winit self.window_id_to_winit.insert(window_id, winit_window.id());
.insert(window.id(), winit_window.id()); self.winit_to_window_id.insert(winit_window.id(), window_id);
self.winit_to_window_id
.insert(winit_window.id(), window.id());
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
{ {
use winit::platform::web::WindowExtWebSys; use winit::platform::web::WindowExtWebSys;
if window.canvas.is_none() { if window_descriptor.canvas.is_none() {
let canvas = winit_window.canvas(); let canvas = winit_window.canvas();
let window = web_sys::window().unwrap(); let window = web_sys::window().unwrap();
@ -101,10 +100,16 @@ impl WinitWindows {
} }
let inner_size = winit_window.inner_size(); let inner_size = winit_window.inner_size();
window.update_physical_size_from_backend(inner_size.width, inner_size.height); let scale_factor = winit_window.scale_factor();
window.update_scale_factor_from_backend(winit_window.scale_factor());
self.windows.insert(winit_window.id(), winit_window); self.windows.insert(winit_window.id(), winit_window);
Window::new(
window_id,
&window_descriptor,
inner_size.width,
inner_size.height,
scale_factor,
)
} }
pub fn get_window(&self, id: WindowId) -> Option<&winit::window::Window> { pub fn get_window(&self, id: WindowId) -> Option<&winit::window::Window> {

View file

@ -238,11 +238,11 @@ fn collision_system(
let win = wins.get_primary().unwrap(); let win = wins.get_primary().unwrap();
let ceiling = win.logical_height() / 2.; let ceiling = win.height() / 2.;
let ground = -(win.logical_height() / 2.); let ground = -(win.height() / 2.);
let wall_left = -(win.logical_width() / 2.); let wall_left = -(win.width() / 2.);
let wall_right = win.logical_width() / 2.; let wall_right = win.width() / 2.;
for (mut v, mut t) in q.iter_mut() { for (mut v, mut t) in q.iter_mut() {
let left = t.translation.x - SPRITE_SIZE / 2.0; let left = t.translation.x - SPRITE_SIZE / 2.0;

View file

@ -48,8 +48,8 @@ fn bounce_system(
mut sprites: Query<(&Transform, &mut Velocity)>, mut sprites: Query<(&Transform, &mut Velocity)>,
) { ) {
let window = windows.get_primary().expect("No primary window."); let window = windows.get_primary().expect("No primary window.");
let width = window.logical_width(); let width = window.width();
let height = window.logical_height(); let height = window.height();
let left = width / -2.0; let left = width / -2.0;
let right = width / 2.0; let right = width / 2.0;
let bottom = height / -2.0; let bottom = height / -2.0;

View file

@ -30,8 +30,8 @@ fn main() {
App::build() App::build()
.add_resource(WindowDescriptor { .add_resource(WindowDescriptor {
title: "BevyMark".to_string(), title: "BevyMark".to_string(),
width: 800, width: 800.,
height: 600, height: 600.,
vsync: true, vsync: true,
resizable: false, resizable: false,
..Default::default() ..Default::default()
@ -85,8 +85,8 @@ fn mouse_handler(
) { ) {
if mouse_button_input.pressed(MouseButton::Left) { if mouse_button_input.pressed(MouseButton::Left) {
let spawn_count = (BIRDS_PER_SECOND as f32 * time.delta_seconds()) as u128; let spawn_count = (BIRDS_PER_SECOND as f32 * time.delta_seconds()) as u128;
let bird_x = (window.width as i32 / -2) as f32 + HALF_BIRD_SIZE; let bird_x = (window.width / -2.) + HALF_BIRD_SIZE;
let bird_y = (window.height / 2) as f32 - HALF_BIRD_SIZE; let bird_y = (window.height / 2.) - HALF_BIRD_SIZE;
for count in 0..spawn_count { for count in 0..spawn_count {
let bird_position = Vec3::new(bird_x, bird_y, (counter.count + count) as f32 * 0.00001); let bird_position = Vec3::new(bird_x, bird_y, (counter.count + count) as f32 * 0.00001);

View file

@ -9,8 +9,8 @@ use bevy::{
fn main() { fn main() {
App::build() App::build()
.add_resource(WindowDescriptor { .add_resource(WindowDescriptor {
width: 300, width: 300.,
height: 300, height: 300.,
..Default::default() ..Default::default()
}) })
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)

View file

@ -35,8 +35,8 @@ fn setup(
create_window_events.send(CreateWindow { create_window_events.send(CreateWindow {
id: window_id, id: window_id,
descriptor: WindowDescriptor { descriptor: WindowDescriptor {
width: 800, width: 800.,
height: 600, height: 600.,
vsync: false, vsync: false,
title: "second window".to_string(), title: "second window".to_string(),
..Default::default() ..Default::default()

View file

@ -5,8 +5,8 @@ fn main() {
App::build() App::build()
.add_resource(WindowDescriptor { .add_resource(WindowDescriptor {
title: "I am a window!".to_string(), title: "I am a window!".to_string(),
width: 500, width: 500.,
height: 300, height: 300.,
vsync: true, vsync: true,
resizable: false, resizable: false,
..Default::default() ..Default::default()