-
-
Notifications
You must be signed in to change notification settings - Fork 3.8k
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
Remove custom rounding #16097
Merged
alice-i-cecile
merged 19 commits into
bevyengine:main
from
ickshonpe:remove-custom-rounding
Oct 28, 2024
Merged
Remove custom rounding #16097
Changes from 16 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
e2b1cb7
Enable taffy's builtin layout coords rounding
ickshonpe 275a06b
Removed the coordinate rounding from `ui_layout_system`.
ickshonpe 4567842
Merge branch 'main' into remove-custom-rounding
ickshonpe 5c7ca68
Changed the initial scaling in the test before the while loop from `1…
ickshonpe 536b784
Update crates/bevy_ui/src/layout/mod.rs
ickshonpe 22fb21f
Merge branch 'main' into remove-custom-rounding
ickshonpe e48b4d8
Modified `ui_rounding_text` so it passes, accuracy not so important w…
ickshonpe 2d1c9e5
Merge branch 'main' into remove-custom-rounding
ickshonpe e0c651a
Merge branch 'main' into remove-custom-rounding
ickshonpe b9985fb
Merge branch 'main' into remove-custom-rounding
ickshonpe 5766f43
Clean up, removed `unrounded_size` field from `Node`
ickshonpe 7b96e5c
Removed too many brackets
ickshonpe 9d80d38
Brought back unrounded sizes
ickshonpe 321f3a6
Merge branch 'main' into remove-custom-rounding
ickshonpe faf5965
Removed the no longer necessary `absolute_location` parameter from `u…
ickshonpe b635211
Merge branch 'remove-custom-rounding' of https://github.com/ickshonpe…
ickshonpe d58f037
Comments and a few renamings of local variables for clarity.
ickshonpe f2d11a8
Merge branch 'main' into remove-custom-rounding
ickshonpe cab2a2a
Merge branch 'main' into remove-custom-rounding
ickshonpe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -296,14 +296,13 @@ with UI components as a child of an entity without UI components, your UI layout | |
update_uinode_geometry_recursive( | ||
&mut commands, | ||
*root, | ||
&ui_surface, | ||
&mut ui_surface, | ||
None, | ||
&mut node_transform_query, | ||
&ui_children, | ||
inverse_target_scale_factor, | ||
Vec2::ZERO, | ||
Vec2::ZERO, | ||
Vec2::ZERO, | ||
); | ||
} | ||
|
||
|
@@ -315,7 +314,7 @@ with UI components as a child of an entity without UI components, your UI layout | |
fn update_uinode_geometry_recursive( | ||
commands: &mut Commands, | ||
entity: Entity, | ||
ui_surface: &UiSurface, | ||
ui_surface: &mut UiSurface, | ||
root_size: Option<Vec2>, | ||
node_transform_query: &mut Query<( | ||
&mut ComputedNode, | ||
|
@@ -329,7 +328,6 @@ with UI components as a child of an entity without UI components, your UI layout | |
inverse_target_scale_factor: f32, | ||
parent_size: Vec2, | ||
parent_scroll_position: Vec2, | ||
mut absolute_location: Vec2, | ||
) { | ||
if let Ok(( | ||
mut node, | ||
|
@@ -340,28 +338,23 @@ with UI components as a child of an entity without UI components, your UI layout | |
maybe_scroll_position, | ||
)) = node_transform_query.get_mut(entity) | ||
{ | ||
let Ok(layout) = ui_surface.get_layout(entity) else { | ||
let Ok((layout, unrounded_unscaled_size)) = ui_surface.get_layout(entity) else { | ||
return; | ||
}; | ||
|
||
let layout_size = | ||
inverse_target_scale_factor * Vec2::new(layout.size.width, layout.size.height); | ||
let unrounded_size = inverse_target_scale_factor * unrounded_unscaled_size; | ||
let layout_location = | ||
inverse_target_scale_factor * Vec2::new(layout.location.x, layout.location.y); | ||
|
||
absolute_location += layout_location; | ||
|
||
let rounded_size = approx_round_layout_coords(absolute_location + layout_size) | ||
- approx_round_layout_coords(absolute_location); | ||
|
||
let rounded_location = | ||
approx_round_layout_coords(layout_location - parent_scroll_position) | ||
+ 0.5 * (rounded_size - parent_size); | ||
layout_location - parent_scroll_position + 0.5 * (layout_size - parent_size); | ||
|
||
// only trigger change detection when the new values are different | ||
if node.calculated_size != rounded_size || node.unrounded_size != layout_size { | ||
node.calculated_size = rounded_size; | ||
node.unrounded_size = layout_size; | ||
if node.calculated_size != layout_size || node.unrounded_size != unrounded_size { | ||
node.calculated_size = layout_size; | ||
node.unrounded_size = unrounded_size; | ||
} | ||
|
||
let taffy_rect_to_border_rect = |rect: taffy::Rect<f32>| BorderRect { | ||
|
@@ -423,11 +416,10 @@ with UI components as a child of an entity without UI components, your UI layout | |
}) | ||
.unwrap_or_default(); | ||
|
||
let round_content_size = approx_round_layout_coords( | ||
let round_content_size = | ||
Vec2::new(layout.content_size.width, layout.content_size.height) | ||
* inverse_target_scale_factor, | ||
); | ||
let max_possible_offset = (round_content_size - rounded_size).max(Vec2::ZERO); | ||
* inverse_target_scale_factor; | ||
let max_possible_offset = (round_content_size - layout_size).max(Vec2::ZERO); | ||
let clamped_scroll_position = scroll_position.clamp(Vec2::ZERO, max_possible_offset); | ||
|
||
if clamped_scroll_position != scroll_position { | ||
|
@@ -445,36 +437,14 @@ with UI components as a child of an entity without UI components, your UI layout | |
node_transform_query, | ||
ui_children, | ||
inverse_target_scale_factor, | ||
rounded_size, | ||
layout_size, | ||
clamped_scroll_position, | ||
absolute_location, | ||
); | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[inline] | ||
/// Round `value` to the nearest whole integer, with ties (values with a fractional part equal to 0.5) rounded towards positive infinity. | ||
fn approx_round_ties_up(value: f32) -> f32 { | ||
(value + 0.5).floor() | ||
} | ||
|
||
#[inline] | ||
/// Rounds layout coordinates by rounding ties upwards. | ||
/// | ||
/// Rounding ties up avoids gaining a pixel when rounding bounds that span from negative to positive. | ||
/// | ||
/// Example: The width between bounds of -50.5 and 49.5 before rounding is 100, using: | ||
/// - `f32::round`: width becomes 101 (rounds to -51 and 50). | ||
/// - `round_ties_up`: width is 100 (rounds to -50 and 50). | ||
fn approx_round_layout_coords(value: Vec2) -> Vec2 { | ||
Vec2 { | ||
x: approx_round_ties_up(value.x), | ||
y: approx_round_ties_up(value.y), | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use taffy::TraversePartialTree; | ||
|
@@ -493,7 +463,7 @@ mod tests { | |
use bevy_hierarchy::{ | ||
despawn_with_children_recursive, BuildChildren, ChildBuild, Children, Parent, | ||
}; | ||
use bevy_math::{vec2, Rect, UVec2, Vec2}; | ||
use bevy_math::{Rect, UVec2, Vec2}; | ||
use bevy_render::{ | ||
camera::{ManualTextureViews, OrthographicProjection}, | ||
prelude::Camera, | ||
|
@@ -510,21 +480,10 @@ mod tests { | |
}; | ||
|
||
use crate::{ | ||
layout::{approx_round_layout_coords, ui_surface::UiSurface}, | ||
prelude::*, | ||
ui_layout_system, | ||
update::update_target_camera_system, | ||
ContentSize, LayoutContext, | ||
layout::ui_surface::UiSurface, prelude::*, ui_layout_system, | ||
update::update_target_camera_system, ContentSize, LayoutContext, | ||
}; | ||
|
||
#[test] | ||
fn round_layout_coords_must_round_ties_up() { | ||
assert_eq!( | ||
approx_round_layout_coords(vec2(-50.5, 49.5)), | ||
vec2(-50., 50.) | ||
); | ||
} | ||
|
||
// these window dimensions are easy to convert to and from percentage values | ||
const WINDOW_WIDTH: f32 = 1000.; | ||
const WINDOW_HEIGHT: f32 = 100.; | ||
|
@@ -598,10 +557,10 @@ mod tests { | |
world.entity_mut(ui_root).add_child(ui_child); | ||
|
||
ui_schedule.run(&mut world); | ||
let ui_surface = world.resource::<UiSurface>(); | ||
let mut ui_surface = world.resource_mut::<UiSurface>(); | ||
|
||
for ui_entity in [ui_root, ui_child] { | ||
let layout = ui_surface.get_layout(ui_entity).unwrap(); | ||
let layout = ui_surface.get_layout(ui_entity).unwrap().0; | ||
assert_eq!(layout.size.width, WINDOW_WIDTH); | ||
assert_eq!(layout.size.height, WINDOW_HEIGHT); | ||
} | ||
|
@@ -955,11 +914,12 @@ mod tests { | |
.get_single(world) | ||
.expect("missing MovingUiNode"); | ||
assert_eq!(expected_camera_entity, target_camera_entity); | ||
let ui_surface = world.resource::<UiSurface>(); | ||
let mut ui_surface = world.resource_mut::<UiSurface>(); | ||
|
||
let layout = ui_surface | ||
.get_layout(ui_node_entity) | ||
.expect("failed to get layout"); | ||
.expect("failed to get layout") | ||
.0; | ||
|
||
// negative test for #12255 | ||
assert_eq!(Vec2::new(layout.location.x, layout.location.y), new_pos); | ||
|
@@ -1043,8 +1003,8 @@ mod tests { | |
|
||
ui_schedule.run(&mut world); | ||
|
||
let ui_surface = world.resource::<UiSurface>(); | ||
let layout = ui_surface.get_layout(ui_entity).unwrap(); | ||
let mut ui_surface = world.resource_mut::<UiSurface>(); | ||
let layout = ui_surface.get_layout(ui_entity).unwrap().0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
// the node should takes its size from the fixed size measure func | ||
assert_eq!(layout.size.width, content_size.x); | ||
|
@@ -1068,25 +1028,25 @@ mod tests { | |
|
||
ui_schedule.run(&mut world); | ||
|
||
let ui_surface = world.resource::<UiSurface>(); | ||
let mut ui_surface = world.resource_mut::<UiSurface>(); | ||
let ui_node = ui_surface.entity_to_taffy[&ui_entity]; | ||
|
||
// a node with a content size should have taffy context | ||
assert!(ui_surface.taffy.get_node_context(ui_node).is_some()); | ||
let layout = ui_surface.get_layout(ui_entity).unwrap(); | ||
let layout = ui_surface.get_layout(ui_entity).unwrap().0; | ||
assert_eq!(layout.size.width, content_size.x); | ||
assert_eq!(layout.size.height, content_size.y); | ||
|
||
world.entity_mut(ui_entity).remove::<ContentSize>(); | ||
|
||
ui_schedule.run(&mut world); | ||
|
||
let ui_surface = world.resource::<UiSurface>(); | ||
let mut ui_surface = world.resource_mut::<UiSurface>(); | ||
// a node without a content size should not have taffy context | ||
assert!(ui_surface.taffy.get_node_context(ui_node).is_none()); | ||
|
||
// Without a content size, the node has no width or height constraints so the length of both dimensions is 0. | ||
let layout = ui_surface.get_layout(ui_entity).unwrap(); | ||
let layout = ui_surface.get_layout(ui_entity).unwrap().0; | ||
assert_eq!(layout.size.width, 0.); | ||
assert_eq!(layout.size.height, 0.); | ||
} | ||
|
@@ -1123,7 +1083,8 @@ mod tests { | |
.collect::<Vec<Entity>>(); | ||
|
||
for r in [2, 3, 5, 7, 11, 13, 17, 19, 21, 23, 29, 31].map(|n| (n as f32).recip()) { | ||
let mut s = r; | ||
// This fails with very small / unrealistic scale values | ||
let mut s = 1. - r; | ||
ickshonpe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
while s <= 5. { | ||
world.resource_mut::<UiScale>().0 = s; | ||
ui_schedule.run(&mut world); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect()
here