From 95c986303aec56cbc0ea503997b9b1d41324207f Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Fri, 11 Dec 2020 20:37:54 -0800 Subject: [PATCH 1/2] run stretch's layout on physical coordinates to fix pixel alignment of the results --- crates/bevy_ui/src/flex/convert.rs | 105 +++++++++++++++-------------- crates/bevy_ui/src/flex/mod.rs | 53 ++++++++++----- 2 files changed, 88 insertions(+), 70 deletions(-) diff --git a/crates/bevy_ui/src/flex/convert.rs b/crates/bevy_ui/src/flex/convert.rs index c19ce3e3deef8..43bb7c839c0cb 100644 --- a/crates/bevy_ui/src/flex/convert.rs +++ b/crates/bevy_ui/src/flex/convert.rs @@ -3,71 +3,72 @@ use crate::{ JustifyContent, PositionType, Style, Val, }; use bevy_math::{Rect, Size}; -use bevy_reflect::Reflect; -fn from_rect(rect: Rect) -> stretch::geometry::Rect -where - T: From, -{ +pub fn from_rect( + scale_factor: f64, + rect: Rect, +) -> stretch::geometry::Rect { stretch::geometry::Rect { - start: rect.left.into(), - end: rect.right.into(), + start: from_val(scale_factor, rect.left), + end: from_val(scale_factor, rect.right), // NOTE: top and bottom are intentionally flipped. stretch has a flipped y-axis - top: rect.bottom.into(), - bottom: rect.top.into(), + top: from_val(scale_factor, rect.bottom), + bottom: from_val(scale_factor, rect.top), } } -fn from_size(size: Size) -> stretch::geometry::Size -where - U: Reflect, - T: From, -{ +pub fn from_f32_size(scale_factor: f64, size: Size) -> stretch::geometry::Size { stretch::geometry::Size { - width: size.width.into(), - height: size.height.into(), + width: (scale_factor * size.width as f64) as f32, + height: (scale_factor * size.height as f64) as f32, } } -impl From<&Style> for stretch::style::Style { - fn from(value: &Style) -> Self { - Self { - overflow: stretch::style::Overflow::Visible, - display: value.display.into(), - position_type: value.position_type.into(), - direction: value.direction.into(), - flex_direction: value.flex_direction.into(), - flex_wrap: value.flex_wrap.into(), - align_items: value.align_items.into(), - align_self: value.align_self.into(), - align_content: value.align_content.into(), - justify_content: value.justify_content.into(), - position: from_rect(value.position), - margin: from_rect(value.margin), - padding: from_rect(value.padding), - border: from_rect(value.border), - flex_grow: value.flex_grow, - flex_shrink: value.flex_shrink, - flex_basis: value.flex_basis.into(), - size: from_size(value.size), - min_size: from_size(value.min_size), - max_size: from_size(value.max_size), - aspect_ratio: match value.aspect_ratio { - Some(value) => stretch::number::Number::Defined(value), - None => stretch::number::Number::Undefined, - }, - } +pub fn from_val_size( + scale_factor: f64, + size: Size, +) -> stretch::geometry::Size { + stretch::geometry::Size { + width: from_val(scale_factor, size.width), + height: from_val(scale_factor, size.height), } } -impl From for stretch::style::Dimension { - fn from(val: Val) -> Self { - match val { - Val::Auto => stretch::style::Dimension::Auto, - Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0), - Val::Px(value) => stretch::style::Dimension::Points(value), - Val::Undefined => stretch::style::Dimension::Undefined, - } +pub fn from_style(scale_factor: f64, value: &Style) -> stretch::style::Style { + stretch::style::Style { + overflow: stretch::style::Overflow::Visible, + display: value.display.into(), + position_type: value.position_type.into(), + direction: value.direction.into(), + flex_direction: value.flex_direction.into(), + flex_wrap: value.flex_wrap.into(), + align_items: value.align_items.into(), + align_self: value.align_self.into(), + align_content: value.align_content.into(), + justify_content: value.justify_content.into(), + position: from_rect(scale_factor, value.position), + margin: from_rect(scale_factor, value.margin), + padding: from_rect(scale_factor, value.padding), + border: from_rect(scale_factor, value.border), + flex_grow: value.flex_grow, + flex_shrink: value.flex_shrink, + flex_basis: from_val(scale_factor, value.flex_basis), + size: from_val_size(scale_factor, value.size), + min_size: from_val_size(scale_factor, value.min_size), + max_size: from_val_size(scale_factor, value.max_size), + aspect_ratio: match value.aspect_ratio { + Some(value) => stretch::number::Number::Defined(value), + None => stretch::number::Number::Undefined, + }, + } +} + +pub fn from_val(scale_factor: f64, val: Val) -> stretch::style::Dimension { + match val { + Val::Auto => stretch::style::Dimension::Auto, + Val::Percent(value) => stretch::style::Dimension::Percent(value / 100.0), + Val::Px(value) => stretch::style::Dimension::Points((scale_factor * value as f64) as f32), + Val::Undefined => stretch::style::Dimension::Undefined, } } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index f8851626d6cf7..fb03570f9f529 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -35,10 +35,10 @@ impl Default for FlexSurface { } impl FlexSurface { - pub fn upsert_node(&mut self, entity: Entity, style: &Style) { + pub fn upsert_node(&mut self, entity: Entity, style: &Style, scale_factor: f64) { let mut added = false; let stretch = &mut self.stretch; - let stretch_style = style.into(); + let stretch_style = convert::from_style(scale_factor, style); let stretch_node = self.entity_to_stretch.entry(entity).or_insert_with(|| { added = true; stretch.new_node(stretch_style, Vec::new()).unwrap() @@ -51,14 +51,17 @@ impl FlexSurface { } } - pub fn upsert_leaf(&mut self, entity: Entity, style: &Style, calculated_size: CalculatedSize) { + pub fn upsert_leaf( + &mut self, + entity: Entity, + style: &Style, + calculated_size: CalculatedSize, + scale_factor: f64, + ) { let stretch = &mut self.stretch; - let stretch_style = style.into(); + let stretch_style = convert::from_style(scale_factor, style); let measure = Box::new(move |constraints: stretch::geometry::Size| { - let mut size = stretch::geometry::Size { - width: calculated_size.size.width, - height: calculated_size.size.height, - }; + let mut size = convert::from_f32_size(scale_factor, calculated_size.size); match (constraints.width, constraints.height) { (Number::Undefined, Number::Undefined) => {} (Number::Defined(width), Number::Undefined) => { @@ -116,8 +119,8 @@ impl FlexSurface { *node, stretch::style::Style { size: stretch::geometry::Size { - width: stretch::style::Dimension::Points(window.width()), - height: stretch::style::Dimension::Points(window.height()), + width: stretch::style::Dimension::Points(window.physical_width() as f32), + height: stretch::style::Dimension::Points(window.physical_height() as f32), }, ..Default::default() }, @@ -174,18 +177,25 @@ pub fn flex_node_system( flex_surface.update_window(window); } + // assume one window for time being... + let l2p_factor = if let Some(primary_window) = windows.get_primary() { + primary_window.scale_factor() + } else { + 1. + }; + // update changed nodes for (entity, style, calculated_size) in node_query.iter() { // TODO: remove node from old hierarchy if its root has changed if let Some(calculated_size) = calculated_size { - flex_surface.upsert_leaf(entity, &style, *calculated_size); + flex_surface.upsert_leaf(entity, &style, *calculated_size, l2p_factor); } else { - flex_surface.upsert_node(entity, &style); + flex_surface.upsert_node(entity, &style, l2p_factor); } } for (entity, style, calculated_size) in changed_size_query.iter() { - flex_surface.upsert_leaf(entity, &style, *calculated_size); + flex_surface.upsert_leaf(entity, &style, *calculated_size, l2p_factor); } // TODO: handle removed nodes @@ -203,16 +213,23 @@ pub fn flex_node_system( // compute layouts flex_surface.compute_window_layouts(); + let p2l_factor = 1. / l2p_factor; + + let to_logical = |v| (p2l_factor * v as f64) as f32; + for (entity, mut node, mut transform, parent) in node_transform_query.iter_mut() { let layout = flex_surface.get_layout(entity).unwrap(); - node.size = Vec2::new(layout.size.width, layout.size.height); + node.size = Vec2::new( + to_logical(layout.size.width), + to_logical(layout.size.height), + ); let position = &mut transform.translation; - position.x = layout.location.x + layout.size.width / 2.0; - position.y = layout.location.y + layout.size.height / 2.0; + position.x = to_logical(layout.location.x + layout.size.width / 2.0); + position.y = to_logical(layout.location.y + layout.size.height / 2.0); if let Some(parent) = parent { if let Ok(parent_layout) = flex_surface.get_layout(parent.0) { - position.x -= parent_layout.size.width / 2.0; - position.y -= parent_layout.size.height / 2.0; + position.x -= to_logical(parent_layout.size.width / 2.0); + position.y -= to_logical(parent_layout.size.height / 2.0); } } } From 799e4b578f24900841480d70f4c99219e531300b Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Mon, 14 Dec 2020 19:26:31 -0800 Subject: [PATCH 2/2] decompress names of conversion factors --- crates/bevy_ui/src/flex/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index fb03570f9f529..5e514424f20af 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -178,7 +178,7 @@ pub fn flex_node_system( } // assume one window for time being... - let l2p_factor = if let Some(primary_window) = windows.get_primary() { + let logical_to_physical_factor = if let Some(primary_window) = windows.get_primary() { primary_window.scale_factor() } else { 1. @@ -188,14 +188,14 @@ pub fn flex_node_system( for (entity, style, calculated_size) in node_query.iter() { // TODO: remove node from old hierarchy if its root has changed if let Some(calculated_size) = calculated_size { - flex_surface.upsert_leaf(entity, &style, *calculated_size, l2p_factor); + flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor); } else { - flex_surface.upsert_node(entity, &style, l2p_factor); + flex_surface.upsert_node(entity, &style, logical_to_physical_factor); } } for (entity, style, calculated_size) in changed_size_query.iter() { - flex_surface.upsert_leaf(entity, &style, *calculated_size, l2p_factor); + flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor); } // TODO: handle removed nodes @@ -213,9 +213,9 @@ pub fn flex_node_system( // compute layouts flex_surface.compute_window_layouts(); - let p2l_factor = 1. / l2p_factor; + let physical_to_logical_factor = 1. / logical_to_physical_factor; - let to_logical = |v| (p2l_factor * v as f64) as f32; + let to_logical = |v| (physical_to_logical_factor * v as f64) as f32; for (entity, mut node, mut transform, parent) in node_transform_query.iter_mut() { let layout = flex_surface.get_layout(entity).unwrap();