mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/fix-text-offset' into 'master'
Rework scaling to never use the logical size directly from the window as it can end up inconsistent with the size used by the renderer depending on the timing Closes #1360 See merge request veloren/veloren!2888
This commit is contained in:
commit
0bfd2e2c5a
@ -42,11 +42,12 @@ impl IcedUi {
|
||||
default_font: Font,
|
||||
scale_mode: ScaleMode,
|
||||
) -> Result<Self, Error> {
|
||||
let scale = Scale::new(window, scale_mode, 1.2);
|
||||
let scale_factor = window.scale_factor();
|
||||
let renderer = window.renderer_mut();
|
||||
let physical_resolution = renderer.resolution();
|
||||
let scale = Scale::new(physical_resolution, scale_factor, scale_mode, 1.2);
|
||||
|
||||
let scaled_resolution = scale.scaled_resolution().map(|e| e as f32);
|
||||
let physical_resolution = renderer.resolution();
|
||||
|
||||
// TODO: examine how much mem fonts take up and reduce clones if significant
|
||||
Ok(Self {
|
||||
@ -97,16 +98,9 @@ impl IcedUi {
|
||||
use iced::window;
|
||||
match event {
|
||||
// Intercept resizing events
|
||||
// TODO: examine if we are handling dpi properly here
|
||||
// ideally these values should be the logical ones
|
||||
Event::Window(window::Event::Resized { width, height }) => {
|
||||
if width != 0 && height != 0 {
|
||||
let new_dims = Vec2::new(width, height);
|
||||
// TODO maybe use u32 in Scale to be consistent with iced
|
||||
// Avoid resetting cache if window size didn't change
|
||||
self.scale_changed |= self.scale.window_resized(new_dims.map(|e| e as f64));
|
||||
}
|
||||
},
|
||||
// We check if the resolution of the renderer has changed to determine if a resize has
|
||||
// occured
|
||||
Event::Window(window::Event::Resized { .. }) => {},
|
||||
// Scale cursor movement events
|
||||
// Note: in some cases the scaling could be off if a resized event occured in the same
|
||||
// frame, in practice this shouldn't be an issue
|
||||
@ -151,9 +145,15 @@ impl IcedUi {
|
||||
clipboard: &mut Clipboard,
|
||||
) -> (Vec<M>, mouse::Interaction) {
|
||||
span!(_guard, "maintain", "IcedUi::maintain");
|
||||
// There could have been a series of resizes that put us back at the original
|
||||
// resolution.
|
||||
// Avoid resetting cache if window size didn't actually change.
|
||||
let resolution_changed = self.scale.surface_resized(renderer.resolution());
|
||||
|
||||
// Handle window resizing, dpi factor change, and scale mode changing
|
||||
if self.scale_changed {
|
||||
if self.scale_changed || resolution_changed {
|
||||
self.scale_changed = false;
|
||||
|
||||
let scaled_resolution = self.scale.scaled_resolution().map(|e| e as f32);
|
||||
self.events
|
||||
.push(Event::Window(iced::window::Event::Resized {
|
||||
|
@ -118,8 +118,8 @@ pub struct Ui {
|
||||
interface_locals: UiBoundLocals,
|
||||
// Consts to specify positions of ingame elements (e.g. Nametags)
|
||||
ingame_locals: Vec<UiBoundLocals>,
|
||||
// Window size for updating scaling
|
||||
window_resized: Option<Vec2<f64>>,
|
||||
// Whether the window was resized since the last maintain, for updating scaling
|
||||
window_resized: bool,
|
||||
// Scale factor changed
|
||||
scale_factor_changed: Option<f64>,
|
||||
// Used to delay cache resizing until after current frame is drawn
|
||||
@ -138,12 +138,17 @@ pub struct Ui {
|
||||
|
||||
impl Ui {
|
||||
pub fn new(window: &mut Window) -> Result<Self, Error> {
|
||||
let scale = Scale::new(window, ScaleMode::Absolute(1.0), 1.0);
|
||||
let win_dims = scale.scaled_resolution().into_array();
|
||||
|
||||
let scale_factor = window.scale_factor();
|
||||
let renderer = window.renderer_mut();
|
||||
|
||||
let physical_resolution = renderer.resolution();
|
||||
let scale = Scale::new(
|
||||
physical_resolution,
|
||||
scale_factor,
|
||||
ScaleMode::Absolute(1.0),
|
||||
1.0,
|
||||
);
|
||||
|
||||
let win_dims = scale.scaled_resolution().into_array();
|
||||
|
||||
let mut ui = UiBuilder::new(win_dims).build();
|
||||
// NOTE: Since we redraw the actual frame each time whether or not the UI needs
|
||||
@ -176,7 +181,7 @@ impl Ui {
|
||||
model: renderer.create_dynamic_model(100),
|
||||
interface_locals,
|
||||
ingame_locals: Vec::new(),
|
||||
window_resized: None,
|
||||
window_resized: false,
|
||||
scale_factor_changed: None,
|
||||
need_cache_resize: false,
|
||||
graphic_replaced: false,
|
||||
@ -290,7 +295,7 @@ impl Ui {
|
||||
match event.0 {
|
||||
Input::Resize(w, h) => {
|
||||
if w > 0.0 && h > 0.0 {
|
||||
self.window_resized = Some(Vec2::new(w, h))
|
||||
self.window_resized = true;
|
||||
}
|
||||
},
|
||||
Input::Touch(touch) => self.ui.handle_event(Input::Touch(Touch {
|
||||
@ -342,12 +347,14 @@ impl Ui {
|
||||
};
|
||||
|
||||
// Handle window resizing.
|
||||
let need_resize = if let Some(new_dims) = self.window_resized.take() {
|
||||
let need_resize = if self.window_resized {
|
||||
self.window_resized = false;
|
||||
let surface_resolution = renderer.resolution();
|
||||
let (old_w, old_h) = self.scale.scaled_resolution().into_tuple();
|
||||
self.scale.window_resized(new_dims);
|
||||
self.scale.surface_resized(surface_resolution);
|
||||
let (w, h) = self.scale.scaled_resolution().into_tuple();
|
||||
self.ui.handle_event(Input::Resize(w, h));
|
||||
self.window_scissor = default_scissor(renderer.resolution());
|
||||
self.window_scissor = default_scissor(surface_resolution);
|
||||
|
||||
// Avoid panic in graphic cache when minimizing.
|
||||
// Avoid resetting cache if window size didn't change
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::window::Window;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
@ -22,20 +21,23 @@ pub struct Scale {
|
||||
mode: ScaleMode,
|
||||
// Current dpi factor
|
||||
scale_factor: f64,
|
||||
// Current logical window size
|
||||
window_dims: Vec2<f64>,
|
||||
// Current pixel size of the window
|
||||
physical_resolution: Vec2<u32>,
|
||||
// TEMP
|
||||
extra_factor: f64,
|
||||
}
|
||||
|
||||
impl Scale {
|
||||
pub fn new(window: &Window, mode: ScaleMode, extra_factor: f64) -> Self {
|
||||
let window_dims = window.logical_size();
|
||||
let scale_factor = window.scale_factor();
|
||||
pub fn new(
|
||||
physical_resolution: Vec2<u32>,
|
||||
scale_factor: f64,
|
||||
mode: ScaleMode,
|
||||
extra_factor: f64,
|
||||
) -> Self {
|
||||
Scale {
|
||||
mode,
|
||||
scale_factor,
|
||||
window_dims,
|
||||
physical_resolution,
|
||||
extra_factor,
|
||||
}
|
||||
}
|
||||
@ -56,36 +58,38 @@ impl Scale {
|
||||
// Get scaling mode transformed to be relative to the window with the same
|
||||
// aspect ratio as the current window
|
||||
pub fn scaling_mode_as_relative(&self) -> ScaleMode {
|
||||
let scale = self.scale_factor_logical();
|
||||
ScaleMode::RelativeToWindow(self.window_dims.map(|e| e / scale))
|
||||
}
|
||||
|
||||
/// Calculate factor to transform between logical coordinates and our scaled
|
||||
/// coordinates.
|
||||
/// Multiply by scaled coordinates to get the logical coordinates
|
||||
pub fn scale_factor_logical(&self) -> f64 {
|
||||
self.extra_factor
|
||||
* match self.mode {
|
||||
ScaleMode::Absolute(scale) => scale / self.scale_factor,
|
||||
ScaleMode::DpiFactor => 1.0,
|
||||
ScaleMode::RelativeToWindow(dims) => {
|
||||
(self.window_dims.x / dims.x).min(self.window_dims.y / dims.y)
|
||||
},
|
||||
}
|
||||
ScaleMode::RelativeToWindow(self.scaled_resolution())
|
||||
}
|
||||
|
||||
/// Calculate factor to transform between physical coordinates and our
|
||||
/// scaled coordinates.
|
||||
/// Multiply by scaled coordinates to get the physical coordinates
|
||||
pub fn scale_factor_physical(&self) -> f64 { self.scale_factor_logical() * self.scale_factor }
|
||||
pub fn scale_factor_physical(&self) -> f64 {
|
||||
self.extra_factor
|
||||
* match self.mode {
|
||||
ScaleMode::Absolute(scale) => scale,
|
||||
ScaleMode::DpiFactor => 1.0 * self.scale_factor,
|
||||
ScaleMode::RelativeToWindow(dims) => (f64::from(self.physical_resolution.x)
|
||||
/ dims.x)
|
||||
.min(f64::from(self.physical_resolution.y) / dims.y),
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate factor to transform between logical coordinates and our scaled
|
||||
/// coordinates.
|
||||
/// Multiply by scaled coordinates to get the logical coordinates
|
||||
///
|
||||
/// Used to scale coordinates from window events (e.g. the mouse cursor
|
||||
/// position)
|
||||
pub fn scale_factor_logical(&self) -> f64 { self.scale_factor_physical() / self.scale_factor }
|
||||
|
||||
/// Updates window size
|
||||
/// Returns true if the value was changed
|
||||
#[allow(clippy::float_cmp)]
|
||||
pub fn window_resized(&mut self, new_dims: Vec2<f64>) -> bool {
|
||||
let old_window_dims = self.window_dims;
|
||||
self.window_dims = new_dims;
|
||||
old_window_dims != self.window_dims
|
||||
pub fn surface_resized(&mut self, new_res: Vec2<u32>) -> bool {
|
||||
let old_res = self.physical_resolution;
|
||||
self.physical_resolution = new_res;
|
||||
old_res != self.physical_resolution
|
||||
}
|
||||
|
||||
/// Updates scale factor
|
||||
@ -98,10 +102,9 @@ impl Scale {
|
||||
}
|
||||
|
||||
/// Get scaled window size.
|
||||
pub fn scaled_resolution(&self) -> Vec2<f64> { self.window_dims / self.scale_factor_logical() }
|
||||
|
||||
/// Get logical window size
|
||||
pub fn logical_resolution(&self) -> Vec2<f64> { self.window_dims }
|
||||
pub fn scaled_resolution(&self) -> Vec2<f64> {
|
||||
self.physical_resolution.map(f64::from) / self.scale_factor_physical()
|
||||
}
|
||||
|
||||
// Transform point from logical to scaled coordinates.
|
||||
pub fn scale_point(&self, point: Vec2<f64>) -> Vec2<f64> { point / self.scale_factor_logical() }
|
||||
|
Loading…
Reference in New Issue
Block a user