Skip to content
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
76c0480
* Added a `transform: Transform` field to `Node`.
ickshonpe Dec 2, 2024
6847c51
Fixed overflow_debug example
ickshonpe Dec 2, 2024
ff39bd4
Use logical units for `Node`'s translation
ickshonpe Dec 2, 2024
96465d1
Merge branch 'main' into node-global-transform
ickshonpe Dec 2, 2024
f6a3dc8
fix for ambiguity detection
ickshonpe Dec 2, 2024
447cea6
Merge branch 'node-global-transform' of https://github.com/ickshonpe/…
ickshonpe Dec 2, 2024
3dc5c2a
Merge branch 'main' into node-global-transform
ickshonpe Feb 17, 2025
67e8315
Fixes for merge
ickshonpe Feb 17, 2025
10833bf
Changed the `Val::resolve` method to always return always return a va…
ickshonpe Mar 5, 2025
e5a59f1
Merge branch 'main' into node-global-transform
ickshonpe Apr 22, 2025
78ddbf3
Merge branch 'main' into node-global-transform
ickshonpe Apr 22, 2025
78a9972
Split up the `Transform` field into separate fields for translation, …
ickshonpe Apr 24, 2025
81d9433
Made new `Node` fields `pub`.
ickshonpe Apr 24, 2025
abeda2b
Updated layout to use new transform fields.
ickshonpe Apr 24, 2025
2c98ce5
Fixed examples
ickshonpe Apr 24, 2025
54fb3ac
negate rotation before applying it in layout updates
ickshonpe Apr 24, 2025
8825583
Added `TransformedNode` type
ickshonpe Apr 24, 2025
40c51b1
Merge branch 'node-global-transform' into node-global-transform-trans…
ickshonpe Apr 24, 2025
085316f
Addeded `transform: Affine2` field to `ComputedNode`.
ickshonpe Apr 24, 2025
0566eeb
Updated remaining rendering modules
ickshonpe Apr 24, 2025
3dfcdfc
Fixed update module
ickshonpe Apr 24, 2025
6c74428
Fixed accessibility module
ickshonpe Apr 24, 2025
1441201
fixed picking
ickshonpe Apr 24, 2025
7243867
Updated doc comments
ickshonpe Apr 24, 2025
96ddbc8
Added contains_point helper functions to ComputedNode
ickshonpe Apr 24, 2025
8112c79
Removed unused
ickshonpe Apr 24, 2025
430b657
updated ComputedNode::transform doc comment
ickshonpe Apr 24, 2025
1f3d3af
Fixed `focus` module.
ickshonpe Apr 24, 2025
bcb8757
Changed picking_backend to check mouse over recursively
ickshonpe Apr 24, 2025
bd59b49
Removed comments.
ickshonpe Apr 25, 2025
09879ec
Updated `ui_root_node_should_act_like_position_absolute` test
ickshonpe Apr 25, 2025
af637c4
Removed unused
ickshonpe Apr 25, 2025
7f5f998
Added `UiVec`, `UiTransform`, `UiGlobalTransform` types.
ickshonpe Apr 25, 2025
ebeaed2
Update `UiGlobalTransform` in ui_layout_system
ickshonpe Apr 25, 2025
8def248
Update everything to use new UI transform components
ickshonpe Apr 25, 2025
59492df
Merge branch 'val-physical-resolve' into node-ui-transform
ickshonpe Apr 25, 2025
0c4ef87
Added resolve method to `UiVec`
ickshonpe Apr 25, 2025
129c279
Use resolve function in ui_layout_system
ickshonpe Apr 25, 2025
27c0718
Fixed spelling mistake
ickshonpe Apr 25, 2025
4c6f9c6
Fixed UI debug overlay extraction
ickshonpe Apr 25, 2025
a42e295
Fixed `UiVec` attributes
ickshonpe Apr 25, 2025
fa613c3
Use object-centered coordinates for uinodes instead of inconsistantly…
ickshonpe Apr 25, 2025
14fe83a
Changed std import for core
ickshonpe Apr 25, 2025
60ebe6d
Fixed redundant explicit link target
ickshonpe Apr 25, 2025
8fa6db5
Renamed `mouse_over` to `cursor_over`
ickshonpe Apr 25, 2025
5ff2495
Added draft release note
ickshonpe Apr 25, 2025
25cdfaa
Fix for md lint
ickshonpe Apr 25, 2025
1069293
md fix
ickshonpe Apr 25, 2025
dc73857
Added `resolve_clip_rect` helper method to `ComputedNode.
ickshonpe Apr 25, 2025
447844e
Moved `clip_check_recursive` to `picking_backend` module.
ickshonpe Apr 25, 2025
a289ca2
Clean up picking_backend
ickshonpe Apr 25, 2025
c1e9a6b
Removed unneeded variable
ickshonpe Apr 25, 2025
04933ec
Removed unused import
ickshonpe Apr 25, 2025
4f28bc1
Fixed `resolve_clip_rect`, Rect::from_center_size takes a size, not a…
ickshonpe Apr 25, 2025
8318286
Made `UiGlobalTransform`'s inner value private.
ickshonpe Apr 25, 2025
e32cdb1
Fixed accessor in debug_overlay
ickshonpe Apr 25, 2025
b9440e2
Added migration guide
ickshonpe Apr 25, 2025
2ac47f5
Added trailing line to migration guide.
ickshonpe Apr 25, 2025
e91c901
updated migration guide
ickshonpe Apr 26, 2025
c6726fa
Fix migration-guide
ickshonpe Apr 26, 2025
836d8c6
Merge branch 'main' into node-global-transform
ickshonpe Apr 26, 2025
b71f014
Merge branch 'main' into node-global-transform
ickshonpe Apr 27, 2025
fb9fc0f
Added `ui_transform` example
ickshonpe Apr 27, 2025
ff42405
update example
ickshonpe Apr 27, 2025
6f06089
use children! in example
ickshonpe Apr 27, 2025
9495d21
rotate by positive angle
ickshonpe Apr 27, 2025
36b8953
rotate text in example
ickshonpe Apr 27, 2025
a532f32
Merge branch 'node-global-transform' of https://github.com/ickshonpe/…
ickshonpe Apr 27, 2025
3a0a499
Merge branch 'main' into node-global-transform
ickshonpe Apr 27, 2025
306d6f1
moved ui_transform to label's parents in example
ickshonpe Apr 28, 2025
7449a32
apply node + UiTransform's translation together
ickshonpe Apr 28, 2025
6674cc7
Merge branch 'node-global-transform' of https://github.com/ickshonpe/…
ickshonpe Apr 28, 2025
93f3ce8
Renamed `UiVec` to `Val2`, added doc comment.
ickshonpe Apr 28, 2025
94714e6
Fixed unresolved doc links
ickshonpe Apr 28, 2025
5882696
Removed default on unit struct
ickshonpe Apr 28, 2025
84b1663
Merge branch 'main' into node-global-transform
ickshonpe Apr 28, 2025
c5afa14
Merge branch 'main' into node-global-transform
ickshonpe Apr 28, 2025
67b4735
Merge branch 'main' into node-global-transform
ickshonpe May 20, 2025
05e874a
Removed useless conversion
ickshonpe May 20, 2025
7ede048
Merge branch 'main' into node-global-transform
ickshonpe May 28, 2025
b4469ea
Fixed unused imports left over after merge.
ickshonpe May 28, 2025
1218ad9
Changed `rect_size` to a `Vec2 in `prepare_uinodes`
ickshonpe May 28, 2025
e4c1f44
Removed unused import.
ickshonpe May 28, 2025
0c76276
Fixed unused imports left over after merge.
ickshonpe May 28, 2025
be00de2
Updated gradients module
ickshonpe May 28, 2025
c261a07
Changed `UiTransform::rotation` to `Rot2`
ickshonpe May 28, 2025
3d84a36
Fixed compute_affine method
ickshonpe May 28, 2025
280cb3e
Merge branch 'node-global-transform' of https://github.com/ickshonpe/…
ickshonpe May 28, 2025
ee33460
Fixed `full_ui` example
ickshonpe May 28, 2025
0c5ca2a
Fixed backticks in comment.
ickshonpe May 28, 2025
92d3b1a
Replaced `from_angle` fns with a single from rotation function taking…
ickshonpe May 28, 2025
f0a582e
Updated `ui_transform` example
ickshonpe May 28, 2025
6b633e3
Updated migration guide
ickshonpe May 28, 2025
ffd6914
Added migration guide for relative cursor position
ickshonpe May 28, 2025
7eddd04
Fixes for migration guide lints
ickshonpe May 28, 2025
0b689c3
Update crates/bevy_ui/src/ui_transform.rs
ickshonpe Jun 9, 2025
b582aaa
Update crates/bevy_ui/src/ui_transform.rs
ickshonpe Jun 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions crates/bevy_ui/src/accessibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ use bevy_ecs::{
system::{Commands, Query},
world::Ref,
};
use bevy_math::Vec3Swizzles;
use bevy_render::camera::CameraUpdateSystem;
use bevy_transform::prelude::GlobalTransform;

use accesskit::{Node, Rect, Role};

Expand All @@ -36,16 +34,10 @@ fn calc_label(
name.map(String::into_boxed_str)
}

fn calc_bounds(
mut nodes: Query<(
&mut AccessibilityNode,
Ref<ComputedNode>,
Ref<GlobalTransform>,
)>,
) {
for (mut accessible, node, transform) in &mut nodes {
if node.is_changed() || transform.is_changed() {
let center = transform.translation().xy();
fn calc_bounds(mut nodes: Query<(&mut AccessibilityNode, Ref<ComputedNode>)>) {
for (mut accessible, node) in &mut nodes {
if node.is_changed() {
let center = node.transform.translation;
let half_size = 0.5 * node.size;
let min = center - half_size;
let max = center + half_size;
Expand Down
41 changes: 4 additions & 37 deletions crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{CalculatedClip, ComputedNode, ComputedNodeTarget, ResolvedBorderRadius, UiStack};
use crate::{CalculatedClip, ComputedNode, ComputedNodeTarget, UiStack};
use bevy_ecs::{
change_detection::DetectChangesMut,
entity::{ContainsEntity, Entity},
Expand All @@ -12,7 +12,6 @@ use bevy_math::{Rect, Vec2};
use bevy_platform::collections::HashMap;
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{camera::NormalizedRenderTarget, prelude::Camera, view::InheritedVisibility};
use bevy_transform::components::GlobalTransform;
use bevy_window::{PrimaryWindow, Window};

use smallvec::SmallVec;
Expand Down Expand Up @@ -133,7 +132,6 @@ pub struct State {
pub struct NodeQuery {
entity: Entity,
node: &'static ComputedNode,
global_transform: &'static GlobalTransform,
interaction: Option<&'static mut Interaction>,
relative_cursor_position: Option<&'static mut RelativeCursorPosition>,
focus_policy: Option<&'static FocusPolicy>,
Expand Down Expand Up @@ -234,10 +232,8 @@ pub fn ui_focus_system(
}
let camera_entity = node.target_camera.camera()?;

let node_rect = Rect::from_center_size(
node.global_transform.translation().truncate(),
node.node.size(),
);
let node_rect =
Rect::from_center_size(node.node.transform.translation, 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 Expand Up @@ -266,13 +262,7 @@ pub fn ui_focus_system(
};

let contains_cursor = relative_cursor_position_component.mouse_over()
&& cursor_position.is_some_and(|point| {
pick_rounded_rect(
*point - node_rect.center(),
node_rect.size(),
node.node.border_radius,
)
});
&& cursor_position.is_some_and(|point| node.node.contains_point(*point));

// Save the relative cursor position to the correct component
if let Some(mut node_relative_cursor_position_component) = node.relative_cursor_position
Expand Down Expand Up @@ -334,26 +324,3 @@ pub fn ui_focus_system(
}
}
}

// Returns true if `point` (relative to the rectangle's center) is within the bounds of a rounded rectangle with
// the given size and border radius.
//
// Matches the sdf function in `ui.wgsl` that is used by the UI renderer to draw rounded rectangles.
pub(crate) fn pick_rounded_rect(
point: Vec2,
size: Vec2,
border_radius: ResolvedBorderRadius,
) -> bool {
let [top, bottom] = if point.x < 0. {
[border_radius.top_left, border_radius.bottom_left]
} else {
[border_radius.top_right, border_radius.bottom_right]
};
let r = if point.y < 0. { top } else { bottom };

let corner_to_point = point.abs() - 0.5 * size;
let q = corner_to_point + r;
let l = q.max(Vec2::ZERO).length();
let m = q.max_element().min(0.);
l + m - r < 0.
}
10 changes: 8 additions & 2 deletions crates/bevy_ui/src/layout/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ impl RepeatedGridTrack {

#[cfg(test)]
mod tests {
use bevy_math::Vec2;

use super::*;

#[test]
Expand Down Expand Up @@ -522,8 +524,12 @@ mod tests {
],
grid_column: GridPlacement::start(4),
grid_row: GridPlacement::span(3),
x_translation: Val::ZERO,
y_translation: Val::ZERO,
scale: Vec2::ONE,
rotation: 0.,
};
let viewport_values = LayoutContext::new(1.0, bevy_math::Vec2::new(800., 600.));
let viewport_values = LayoutContext::new(1.0, Vec2::new(800., 600.));
let taffy_style = from_node(&node, &viewport_values, false);
assert_eq!(taffy_style.display, taffy::style::Display::Flex);
assert_eq!(taffy_style.box_sizing, taffy::style::BoxSizing::ContentBox);
Expand Down Expand Up @@ -661,7 +667,7 @@ mod tests {
#[test]
fn test_into_length_percentage() {
use taffy::style::LengthPercentage;
let context = LayoutContext::new(2.0, bevy_math::Vec2::new(800., 600.));
let context = LayoutContext::new(2.0, Vec2::new(800., 600.));
let cases = [
(Val::Auto, LengthPercentage::Length(0.)),
(Val::Percent(1.), LengthPercentage::Percent(0.01)),
Expand Down
45 changes: 31 additions & 14 deletions crates/bevy_ui/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ use bevy_ecs::{
system::{Commands, Query, ResMut},
world::Ref,
};
use bevy_math::Vec2;

use bevy_math::{Affine2, Vec2};
use bevy_sprite::BorderRect;
use bevy_transform::components::Transform;
use thiserror::Error;
use tracing::warn;
use ui_surface::UiSurface;
Expand Down Expand Up @@ -81,9 +81,8 @@ pub fn ui_layout_system(
)>,
computed_node_query: Query<(Entity, Option<Ref<ChildOf>>), With<ComputedNode>>,
ui_children: UiChildren,
mut node_transform_query: Query<(
mut node_update_query: Query<(
&mut ComputedNode,
&mut Transform,
&Node,
Option<&LayoutConfig>,
Option<&BorderRadius>,
Expand Down Expand Up @@ -175,7 +174,8 @@ with UI components as a child of an entity without UI components, your UI layout
&mut ui_surface,
true,
None,
&mut node_transform_query,
Affine2::IDENTITY,
&mut node_update_query,
&ui_children,
computed_target.scale_factor.recip(),
Vec2::ZERO,
Expand All @@ -190,9 +190,9 @@ with UI components as a child of an entity without UI components, your UI layout
ui_surface: &mut UiSurface,
inherited_use_rounding: bool,
root_size: Option<Vec2>,
node_transform_query: &mut Query<(
mut transform: Affine2,
node_update_query: &mut Query<(
&mut ComputedNode,
&mut Transform,
&Node,
Option<&LayoutConfig>,
Option<&BorderRadius>,
Expand All @@ -206,13 +206,12 @@ with UI components as a child of an entity without UI components, your UI layout
) {
if let Ok((
mut node,
mut transform,
style,
maybe_layout_config,
maybe_border_radius,
maybe_outline,
maybe_scroll_position,
)) = node_transform_query.get_mut(entity)
)) = node_update_query.get_mut(entity)
{
let use_rounding = maybe_layout_config
.map(|layout_config| layout_config.use_rounding)
Expand Down Expand Up @@ -255,6 +254,27 @@ with UI components as a child of an entity without UI components, your UI layout

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

let resolve_translation = |mut val: Val, extent: f32, viewport_size: Vec2| {
if let Val::Px(ref mut value) = val {
*value /= inverse_target_scale_factor
}
val.resolve(extent, viewport_size).unwrap_or(0.)
};

let node_transform = Affine2::from_scale_angle_translation(
style.scale,
-style.rotation,
Vec2::new(
resolve_translation(style.x_translation, layout_size.x, viewport_size),
resolve_translation(style.y_translation, layout_size.y, viewport_size),
),
);
transform *= node_transform * Affine2::from_translation(node_center);

if transform != node.transform {
node.transform = transform;
}

if let Some(border_radius) = maybe_border_radius {
// We don't trigger change detection for changes to border radius
node.bypass_change_detection().border_radius = border_radius.resolve(
Expand Down Expand Up @@ -288,10 +308,6 @@ with UI components as a child of an entity without UI components, your UI layout
.max(0.);
}

if transform.translation.truncate() != node_center {
transform.translation = node_center.extend(0.);
}

let scroll_position: Vec2 = maybe_scroll_position
.map(|scroll_pos| {
Vec2::new(
Expand Down Expand Up @@ -331,7 +347,8 @@ with UI components as a child of an entity without UI components, your UI layout
ui_surface,
use_rounding,
Some(viewport_size),
node_transform_query,
transform,
node_update_query,
ui_children,
inverse_target_scale_factor,
layout_size,
Expand Down
15 changes: 3 additions & 12 deletions crates/bevy_ui/src/picking_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@

#![deny(missing_docs)]

use crate::{focus::pick_rounded_rect, prelude::*, UiStack};
use crate::{prelude::*, UiStack};
use bevy_app::prelude::*;
use bevy_ecs::{prelude::*, query::QueryData};
use bevy_math::{Rect, Vec2};
use bevy_platform::collections::HashMap;
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::prelude::*;
use bevy_transform::prelude::*;
use bevy_window::PrimaryWindow;

use bevy_picking::backend::prelude::*;
Expand Down Expand Up @@ -91,7 +90,6 @@ impl Plugin for UiPickingPlugin {
pub struct NodeQuery {
entity: Entity,
node: &'static ComputedNode,
global_transform: &'static GlobalTransform,
pickable: Option<&'static Pickable>,
calculated_clip: Option<&'static CalculatedClip>,
inherited_visibility: Option<&'static InheritedVisibility>,
Expand Down Expand Up @@ -186,10 +184,7 @@ pub fn ui_picking(
continue;
};

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

// Nodes with Display::None have a (0., 0.) logical rect and can be ignored
if node_rect.size() == Vec2::ZERO {
Expand All @@ -213,11 +208,7 @@ pub fn ui_picking(
if visible_rect
.normalize(node_rect)
.contains(relative_cursor_position)
&& pick_rounded_rect(
*cursor_position - node_rect.center(),
node_rect.size(),
node.node.border_radius,
)
&& node.node.contains_point(*cursor_position)
{
hit_nodes
.entry((camera_entity, *pointer_id))
Expand Down
24 changes: 13 additions & 11 deletions crates/bevy_ui/src/render/box_shadow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use bevy_ecs::{
},
};
use bevy_image::BevyDefault as _;
use bevy_math::{vec2, FloatOrd, Mat4, Rect, Vec2, Vec3Swizzles, Vec4Swizzles};
use bevy_math::{vec2, Affine2, FloatOrd, Rect, Vec2};
use bevy_render::sync_world::MainEntity;
use bevy_render::RenderApp;
use bevy_render::{
Expand All @@ -29,7 +29,6 @@ use bevy_render::{
view::*,
Extract, ExtractSchedule, Render, RenderSet,
};
use bevy_transform::prelude::GlobalTransform;
use bytemuck::{Pod, Zeroable};

use super::{stack_z_offsets, UiCameraMap, UiCameraView, QUAD_INDICES, QUAD_VERTEX_POSITIONS};
Expand Down Expand Up @@ -215,7 +214,7 @@ impl SpecializedRenderPipeline for BoxShadowPipeline {
/// Description of a shadow to be sorted and queued for rendering
pub struct ExtractedBoxShadow {
pub stack_index: u32,
pub transform: Mat4,
pub transform: Affine2,
pub bounds: Vec2,
pub clip: Option<Rect>,
pub extracted_camera_entity: Entity,
Expand All @@ -240,7 +239,6 @@ pub fn extract_shadows(
Query<(
Entity,
&ComputedNode,
&GlobalTransform,
&InheritedVisibility,
&BoxShadow,
Option<&CalculatedClip>,
Expand All @@ -251,7 +249,7 @@ pub fn extract_shadows(
) {
let mut mapping = camera_map.get_mapper();

for (entity, uinode, transform, visibility, box_shadow, clip, camera) in &box_shadow_query {
for (entity, uinode, visibility, box_shadow, clip, camera) in &box_shadow_query {
// Skip if no visible shadows
if !visibility.get() || box_shadow.is_empty() || uinode.is_empty() {
continue;
Expand Down Expand Up @@ -306,7 +304,7 @@ pub fn extract_shadows(
extracted_box_shadows.box_shadows.push(ExtractedBoxShadow {
render_entity: commands.spawn(TemporaryRenderEntity).id(),
stack_index: uinode.stack_index,
transform: transform.compute_matrix() * Mat4::from_translation(offset.extend(0.)),
transform: uinode.transform * Affine2::from_translation(offset),
color: drop_shadow.color.into(),
bounds: shadow_size + 6. * blur_radius,
clip: clip.map(|clip| clip.clip),
Expand Down Expand Up @@ -409,11 +407,15 @@ pub fn prepare_shadows(
.get(item.index)
.filter(|n| item.entity() == n.render_entity)
{
let rect_size = box_shadow.bounds.extend(1.0);
let rect_size = box_shadow.bounds;

// Specify the corners of the node
let positions = QUAD_VERTEX_POSITIONS
.map(|pos| (box_shadow.transform * (pos * rect_size).extend(1.)).xyz());
let positions = QUAD_VERTEX_POSITIONS.map(|pos| {
box_shadow
.transform
.transform_point2(pos * rect_size)
.extend(0.)
});

// Calculate the effect of clipping
// Note: this won't work with rotation/scaling, but that's much more complex (may need more that 2 quads)
Expand Down Expand Up @@ -447,7 +449,7 @@ pub fn prepare_shadows(
positions[3] + positions_diff[3].extend(0.),
];

let transformed_rect_size = box_shadow.transform.transform_vector3(rect_size);
let transformed_rect_size = box_shadow.transform.transform_vector2(rect_size);

// Don't try to cull nodes that have a rotation
// In a rotation around the Z-axis, this value is 0.0 for an angle of 0.0 or π
Expand Down Expand Up @@ -496,7 +498,7 @@ pub fn prepare_shadows(
size: box_shadow.size.into(),
radius,
blur: box_shadow.blur_radius,
bounds: rect_size.xy().into(),
bounds: rect_size.into(),
});
}

Expand Down
Loading