Skip to content

Commit

Permalink
use precomputed border values (#15163)
Browse files Browse the repository at this point in the history
# Objective

Fixes #15142

## Solution

* Moved all the UI border geometry calculations that were scattered
through the UI extraction functions into `ui_layout_system`.
* Added a `border: BorderRect` field to `Node` to store the border size
computed by `ui_layout_system`.
* Use the border values returned from Taffy rather than calculate them
ourselves during extraction.
* Removed the `logical_rect` and `physical_rect` methods from `Node` the
descriptions and namings are deceptive, it's better to create the rects
manually instead.
* Added a method `outline_radius` to `Node` that calculates the border
radius of outlines.
* For border values `ExtractedUiNode` takes `BorderRect` and
`ResolvedBorderRadius` now instead of raw `[f32; 4]` values and converts
them in `prepare_uinodes`.
* Removed some unnecessary scaling and clamping of border values
(#15142).
* Added a `BorderRect::ZERO` constant.
* Added an `outlined_node_size` method to `Node`.

## Testing

Added some non-uniform borders to the border example. Everything seems
to be in order:

<img width="626" alt="nub"
src="https://github.com/user-attachments/assets/258ed8b5-1a9e-4ac5-99c2-6bf25c0ef31c">

## Migration Guide

The `logical_rect` and `physical_rect` methods have been removed from
`Node`. Use `Rect::from_center_size` with the translation and node size
instead.

The types of the fields border and border_radius of `ExtractedUiNode`
have been changed to `BorderRect` and `ResolvedBorderRadius`
respectively.

---------

Co-authored-by: UkoeHB <[email protected]>
Co-authored-by: akimakinai <[email protected]>
  • Loading branch information
3 people authored Sep 26, 2024
1 parent 35d1086 commit 0fe33c3
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 321 deletions.
3 changes: 3 additions & 0 deletions crates/bevy_sprite/src/texture_slice/border_rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub struct BorderRect {
}

impl BorderRect {
/// An empty border with zero padding values in each direction
pub const ZERO: Self = Self::square(0.);

/// Creates a new border as a square, with identical pixel padding values on every direction
#[must_use]
#[inline]
Expand Down
5 changes: 4 additions & 1 deletion crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,10 @@ pub fn ui_focus_system(
.map(TargetCamera::entity)
.or(default_ui_camera.get())?;

let node_rect = node.node.logical_rect(node.global_transform);
let node_rect = Rect::from_center_size(
node.global_transform.translation().truncate(),
node.node.size(),
);

// Intersect with the calculated clip rect to find the bounds of the visible region of the node
let visible_rect = node
Expand Down
31 changes: 23 additions & 8 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
BorderRadius, ContentSize, DefaultUiCamera, Node, Outline, OverflowAxis, ScrollPosition, Style,
TargetCamera, UiScale,
BorderRadius, ContentSize, DefaultUiCamera, Display, Node, Outline, OverflowAxis,
ScrollPosition, Style, TargetCamera, UiScale,
};
use bevy_ecs::{
change_detection::{DetectChanges, DetectChangesMut},
Expand All @@ -14,6 +14,7 @@ use bevy_ecs::{
use bevy_hierarchy::{Children, Parent};
use bevy_math::{UVec2, Vec2};
use bevy_render::camera::{Camera, NormalizedRenderTarget};
use bevy_sprite::BorderRect;
#[cfg(feature = "bevy_text")]
use bevy_text::{CosmicBuffer, TextPipeline};
use bevy_transform::components::Transform;
Expand Down Expand Up @@ -344,6 +345,13 @@ pub fn ui_layout_system(
node.unrounded_size = layout_size;
}

node.bypass_change_detection().border = BorderRect {
left: layout.border.left * inverse_target_scale_factor,
right: layout.border.right * inverse_target_scale_factor,
top: layout.border.top * inverse_target_scale_factor,
bottom: layout.border.bottom * inverse_target_scale_factor,
};

let viewport_size = root_size.unwrap_or(node.calculated_size);

if let Some(border_radius) = maybe_border_radius {
Expand All @@ -355,11 +363,15 @@ pub fn ui_layout_system(
if let Some(outline) = maybe_outline {
// don't trigger change detection when only outlines are changed
let node = node.bypass_change_detection();
node.outline_width = outline
.width
.resolve(node.size().x, viewport_size)
.unwrap_or(0.)
.max(0.);
node.outline_width = if style.display != Display::None {
outline
.width
.resolve(node.size().x, viewport_size)
.unwrap_or(0.)
.max(0.)
} else {
0.
};

node.outline_offset = outline
.offset
Expand Down Expand Up @@ -834,7 +846,10 @@ mod tests {
.fold(
Option::<(Rect, bool)>::None,
|option_rect, (entity, node, global_transform)| {
let current_rect = node.logical_rect(global_transform);
let current_rect = Rect::from_center_size(
global_transform.translation().truncate(),
node.size(),
);
assert!(
current_rect.height().abs() + current_rect.width().abs() > 0.,
"root ui node {entity:?} doesn't have a logical size"
Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_ui/src/picking_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
use crate::{focus::pick_rounded_rect, prelude::*, UiStack};
use bevy_app::prelude::*;
use bevy_ecs::{prelude::*, query::QueryData};
use bevy_math::Vec2;
use bevy_math::{Rect, Vec2};
use bevy_render::prelude::*;
use bevy_transform::prelude::*;
use bevy_utils::hashbrown::HashMap;
Expand Down Expand Up @@ -139,7 +139,10 @@ pub fn ui_picking(
continue;
};

let node_rect = node.node.logical_rect(node.global_transform);
let node_rect = Rect::from_center_size(
node.global_transform.translation().truncate(),
node.node.size(),
);

// Nodes with Display::None have a (0., 0.) logical rect and can be ignored
if node_rect.size() == Vec2::ZERO {
Expand Down
Loading

0 comments on commit 0fe33c3

Please sign in to comment.