run stretch's layout on physical coordinates to fix pixel alignment (#1061)
run stretch's layout on physical coordinates to fix pixel alignment of the results
This commit is contained in:
		
							parent
							
								
									2e2423139e
								
							
						
					
					
						commit
						51650f114f
					
				@ -3,71 +3,72 @@ use crate::{
 | 
			
		||||
    JustifyContent, PositionType, Style, Val,
 | 
			
		||||
};
 | 
			
		||||
use bevy_math::{Rect, Size};
 | 
			
		||||
use bevy_reflect::Reflect;
 | 
			
		||||
 | 
			
		||||
fn from_rect<T, U: Reflect>(rect: Rect<U>) -> stretch::geometry::Rect<T>
 | 
			
		||||
where
 | 
			
		||||
    T: From<U>,
 | 
			
		||||
{
 | 
			
		||||
pub fn from_rect(
 | 
			
		||||
    scale_factor: f64,
 | 
			
		||||
    rect: Rect<Val>,
 | 
			
		||||
) -> stretch::geometry::Rect<stretch::style::Dimension> {
 | 
			
		||||
    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<T, U>(size: Size<U>) -> stretch::geometry::Size<T>
 | 
			
		||||
where
 | 
			
		||||
    U: Reflect,
 | 
			
		||||
    T: From<U>,
 | 
			
		||||
{
 | 
			
		||||
pub fn from_f32_size(scale_factor: f64, size: Size<f32>) -> stretch::geometry::Size<f32> {
 | 
			
		||||
    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<Val>,
 | 
			
		||||
) -> stretch::geometry::Size<stretch::style::Dimension> {
 | 
			
		||||
    stretch::geometry::Size {
 | 
			
		||||
        width: from_val(scale_factor, size.width),
 | 
			
		||||
        height: from_val(scale_factor, size.height),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<Val> 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,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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<Number>| {
 | 
			
		||||
            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 logical_to_physical_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, logical_to_physical_factor);
 | 
			
		||||
        } else {
 | 
			
		||||
            flex_surface.upsert_node(entity, &style);
 | 
			
		||||
            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);
 | 
			
		||||
        flex_surface.upsert_leaf(entity, &style, *calculated_size, logical_to_physical_factor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: handle removed nodes
 | 
			
		||||
@ -203,16 +213,23 @@ pub fn flex_node_system(
 | 
			
		||||
    // compute layouts
 | 
			
		||||
    flex_surface.compute_window_layouts();
 | 
			
		||||
 | 
			
		||||
    let physical_to_logical_factor = 1. / logical_to_physical_factor;
 | 
			
		||||
 | 
			
		||||
    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();
 | 
			
		||||
        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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user