Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Round UI coordinates after scaling #9784

Merged
merged 9 commits into from
Sep 18, 2023
79 changes: 67 additions & 12 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,24 +317,23 @@ pub fn ui_layout_system(
) {
if let Ok((mut node, mut transform)) = node_transform_query.get_mut(entity) {
let layout = ui_surface.get_layout(entity).unwrap();
let layout_size = Vec2::new(layout.size.width, layout.size.height);
let layout_location = Vec2::new(layout.location.x, layout.location.y);
let layout_size =
inverse_target_scale_factor * Vec2::new(layout.size.width, layout.size.height);
let layout_location =
inverse_target_scale_factor * Vec2::new(layout.location.x, layout.location.y);

absolute_location += layout_location;
let rounded_location = round_layout_coords(layout_location);
let rounded_size = round_layout_coords(absolute_location + layout_size)
- round_layout_coords(absolute_location);

let new_size = inverse_target_scale_factor * rounded_size;
let new_position =
inverse_target_scale_factor * rounded_location + 0.5 * (new_size - parent_size);
let rounded_location =
round_layout_coords(layout_location) + 0.5 * (rounded_size - parent_size);

// only trigger change detection when the new values are different
if node.calculated_size != new_size {
node.calculated_size = new_size;
if node.calculated_size != rounded_size {
node.calculated_size = rounded_size;
}
if transform.translation.truncate() != new_position {
transform.translation = new_position.extend(0.);
if transform.translation.truncate() != rounded_location {
transform.translation = rounded_location.extend(0.);
}
if let Ok(children) = children_query.get(entity) {
for &child_uinode in children {
Expand All @@ -344,7 +343,7 @@ pub fn ui_layout_system(
node_transform_query,
children_query,
inverse_target_scale_factor,
new_size,
rounded_size,
absolute_location,
);
}
Expand Down Expand Up @@ -400,11 +399,13 @@ mod tests {
use crate::ui_layout_system;
use crate::ContentSize;
use crate::UiSurface;
use bevy_ecs::entity::Entity;
use bevy_ecs::event::Events;
use bevy_ecs::schedule::Schedule;
use bevy_ecs::world::World;
use bevy_hierarchy::despawn_with_children_recursive;
use bevy_hierarchy::BuildWorldChildren;
use bevy_hierarchy::Children;
use bevy_math::vec2;
use bevy_math::Vec2;
use bevy_utils::prelude::default;
Expand Down Expand Up @@ -714,4 +715,58 @@ mod tests {
assert_eq!(layout.size.width, 0.);
assert_eq!(layout.size.height, 0.);
}

#[test]
fn ui_rounding_test() {
let (mut world, mut ui_schedule) = setup_ui_test_world();

let parent = world
.spawn(NodeBundle {
style: Style {
display: Display::Grid,
grid_template_columns: RepeatedGridTrack::min_content(2),
margin: UiRect::all(Val::Px(4.0)),
..Default::default()
},
..Default::default()
})
.with_children(|commands| {
for _ in 0..2 {
commands.spawn(NodeBundle {
style: Style {
display: Display::Grid,
width: Val::Px(160.),
height: Val::Px(160.),
..Default::default()
},
..Default::default()
});
}
})
.id();

let children = world
.entity(parent)
.get::<Children>()
.unwrap()
.iter()
.copied()
.collect::<Vec<Entity>>();

for r in [2, 3, 5, 7, 11, 13, 17, 19, 21, 23, 29, 31].map(|n| (n as f64).recip()) {
let mut s = r;
while s <= 5. {
world.resource_mut::<UiScale>().0 = s;
ui_schedule.run(&mut world);
let width_sum: f32 = children
.iter()
.map(|child| world.get::<Node>(*child).unwrap().calculated_size.x)
.sum();
let parent_width = world.get::<Node>(parent).unwrap().calculated_size.x;
assert!((width_sum - parent_width).abs() < 0.001);
assert!((width_sum - 320.).abs() <= 1.);
s += r;
}
}
}
}