From 471d9fde5761dc3b6d6bc993eb9346d2ed78b7d2 Mon Sep 17 00:00:00 2001 From: David Curthoys Date: Thu, 3 Feb 2022 00:21:09 +0000 Subject: [PATCH 1/6] # Objective - Overflow::Hidden doesn't work correctly with scale_factor_override. - If you run the bevy Ui example with scale_factor_override 3 you'll see half clipped text around the edges of the scrolling listbox. - The problem seems to be that the corners of the node are transformed before the amount of clipping required is calculated. But then that transformed clipping is compared to the original untransformed size of the node rect to see if it should be culled or not. With a higher scale factor the relative size of the untransformed node rect is going to be really big so the overflow isn't culled. # Solution - Multiply the size of the node rect by the extracted_uinode transform before performing the cull test. --- crates/bevy_ui/src/render/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index e632b4eee18cb..63a4214274538 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -344,9 +344,12 @@ pub fn prepare_uinodes( positions[3] + positions_diff[3].extend(0.), ]; + let rect_size_v4 = uinode_rect.size().extend(0.).extend(0.); + let transformed_rect_size = (extracted_uinode.transform * rect_size_v4).xy().extend(1.); + // Cull nodes that are completely clipped - if positions_diff[0].x - positions_diff[1].x >= rect_size.x - || positions_diff[1].y - positions_diff[2].y >= rect_size.y + if positions_diff[0].x - positions_diff[1].x >= transformed_rect_size.x + || positions_diff[1].y - positions_diff[2].y >= transformed_rect_size.y { continue; } From f50516169e407ef1844cf1c68e9a4413b7ba01c0 Mon Sep 17 00:00:00 2001 From: David Curthoys Date: Thu, 3 Feb 2022 01:43:06 +0000 Subject: [PATCH 2/6] Removed the extend on transformed_rect_size that added an unnecessary z component. --- crates/bevy_ui/src/render/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 63a4214274538..db93136e60e63 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -344,8 +344,9 @@ pub fn prepare_uinodes( positions[3] + positions_diff[3].extend(0.), ]; - let rect_size_v4 = uinode_rect.size().extend(0.).extend(0.); - let transformed_rect_size = (extracted_uinode.transform * rect_size_v4).xy().extend(1.); + + let transformed_rect_size = + (extracted_uinode.transform * uinode_rect.size().extend(0.).extend(0.)).xy(); // Cull nodes that are completely clipped if positions_diff[0].x - positions_diff[1].x >= transformed_rect_size.x From 47b596937a1c1e7aa26bd2d51b5563af831a14cf Mon Sep 17 00:00:00 2001 From: David Curthoys Date: Thu, 3 Feb 2022 07:49:02 +0000 Subject: [PATCH 3/6] Replaced the extend and swizzle xy() mess with a single line that uses the transform_point3 Mat4 function. --- crates/bevy_ui/src/render/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index db93136e60e63..d2a2f36d67faf 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -344,9 +344,7 @@ pub fn prepare_uinodes( positions[3] + positions_diff[3].extend(0.), ]; - - let transformed_rect_size = - (extracted_uinode.transform * uinode_rect.size().extend(0.).extend(0.)).xy(); + let transformed_rect_size = extracted_uinode.transform.transform_point3(rect_size); // Cull nodes that are completely clipped if positions_diff[0].x - positions_diff[1].x >= transformed_rect_size.x From f024096bd184064d12adcf81cbc86e4744cbb828 Mon Sep 17 00:00:00 2001 From: David Curthoys Date: Thu, 3 Feb 2022 13:29:11 +0000 Subject: [PATCH 4/6] Previous change was incorrect. Should have been transform_vector3, not transform_point3. Fixed. --- crates/bevy_ui/src/render/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index d2a2f36d67faf..7fd0af4228c1c 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -344,7 +344,7 @@ pub fn prepare_uinodes( positions[3] + positions_diff[3].extend(0.), ]; - let transformed_rect_size = extracted_uinode.transform.transform_point3(rect_size); + let transformed_rect_size = extracted_uinode.transform.transform_vector3(rect_size); // Cull nodes that are completely clipped if positions_diff[0].x - positions_diff[1].x >= transformed_rect_size.x From d87f9979ad18f19a999e4c0893573cb48f4805d2 Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sun, 6 Feb 2022 21:55:41 +0000 Subject: [PATCH 5/6] Implements std::ops operator traits for Mut. # Objective No one likes how tuple structs and Mut force you to write things like: health.0 += 10; # Solution Implement AddAssign on Mut. impl <'a, T, U> AddAssign for Mut<'a, T> where T: AddAssign { fn add_assign(&mut self, rhs: U) { *self.value += rhs; } } then in our game impl AddAssign for Health { fn add_assign(&mut self, rhs: u32) { self.0 += rhs.0; } } pub fn health_system( mut query: Query<&mut Health> ) { query.for_each_mut(|mut health| { health += 10; }); } --- crates/bevy_ecs/src/change_detection.rs | 241 +++++++++++++++++++++++- 1 file changed, 240 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 369d9ecfab486..355e1796c20a2 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -3,7 +3,11 @@ use crate::{component::ComponentTicks, system::Resource}; #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; -use std::ops::{Deref, DerefMut}; +use std::ops::{ + Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Deref, DerefMut, Div, DivAssign, Index, + IndexMut, Mul, MulAssign, Neg, Not, RangeBounds, Rem, RemAssign, Shl, ShlAssign, Shr, + ShrAssign, Sub, SubAssign, +}; /// Types that implement reliable change detection. /// @@ -184,6 +188,241 @@ pub struct Mut<'a, T> { pub(crate) ticks: Ticks<'a>, } +impl<'a, T, U, V> Add for Mut<'a, T> +where + T: Add + Copy, +{ + type Output = V; + + fn add(self, rhs: U) -> Self::Output { + *self.value + rhs + } +} + +impl<'a, T, U> AddAssign for Mut<'a, T> +where + T: AddAssign, +{ + fn add_assign(&mut self, rhs: U) { + *self.value += rhs; + } +} + +impl<'a, T, U, V> BitAnd for Mut<'a, T> +where + T: BitAnd + Copy, +{ + type Output = V; + + fn bitand(self, rhs: U) -> Self::Output { + *self & rhs + } +} + +impl<'a, T, U, V> BitOr for Mut<'a, T> +where + T: BitOr + Copy, +{ + type Output = V; + + fn bitor(self, rhs: U) -> Self::Output { + *self | rhs + } +} + +impl<'a, T, U> BitOrAssign for Mut<'a, T> +where + T: BitOrAssign, +{ + fn bitor_assign(&mut self, rhs: U) { + *self.value |= rhs; + } +} + +impl<'a, T, U, V> BitXor for Mut<'a, T> +where + T: BitXor + Copy, +{ + type Output = V; + + fn bitxor(self, rhs: U) -> Self::Output { + *self ^ rhs + } +} + +impl<'a, T, U> Div for Mut<'a, T> +where + T: Div + Copy, +{ + type Output = T; + + fn div(self, rhs: U) -> Self::Output { + *self.value / rhs + } +} + +impl<'a, T, U> DivAssign for Mut<'a, T> +where + T: DivAssign, +{ + fn div_assign(&mut self, rhs: U) { + *self.value /= rhs; + } +} + +impl<'a, T, U> Mul for Mut<'a, T> +where + T: Mul + Copy, +{ + type Output = T; + + fn mul(self, rhs: U) -> Self::Output { + *self.value * rhs + } +} + +impl<'a, T, U> MulAssign for Mut<'a, T> +where + T: MulAssign, +{ + fn mul_assign(&mut self, rhs: U) { + *self.value *= rhs; + } +} + +impl<'a, T> RangeBounds for Mut<'a, T> +where + T: RangeBounds, +{ + fn start_bound(&self) -> std::ops::Bound<&T> { + self.as_ref().start_bound() + } + + fn end_bound(&self) -> std::ops::Bound<&T> { + self.as_ref().end_bound() + } +} + +impl<'a, T, U> Rem for Mut<'a, T> +where + T: Rem + Copy, +{ + type Output = U; + fn rem(self, rhs: T) -> Self::Output { + *self % rhs + } +} + +impl<'a, T, U> RemAssign for Mut<'a, T> +where + T: RemAssign, +{ + fn rem_assign(&mut self, rhs: U) { + *self.value %= rhs; + } +} + +impl<'a, T, U> Shl for Mut<'a, T> +where + T: Shl + Copy, +{ + type Output = U; + fn shl(self, rhs: T) -> Self::Output { + *self << rhs + } +} + +impl<'a, T, U> ShlAssign for Mut<'a, T> +where + T: ShlAssign, +{ + fn shl_assign(&mut self, rhs: U) { + *self.value <<= rhs; + } +} + +impl<'a, T, U> Shr for Mut<'a, T> +where + T: Shr + Copy, +{ + type Output = U; + fn shr(self, rhs: T) -> Self::Output { + *self >> rhs + } +} + +impl<'a, T, U> ShrAssign for Mut<'a, T> +where + T: ShrAssign, +{ + fn shr_assign(&mut self, rhs: U) { + *self.value >>= rhs; + } +} + +impl<'a, T, U> SubAssign for Mut<'a, T> +where + T: SubAssign, +{ + fn sub_assign(&mut self, rhs: U) { + *self.value -= rhs; + } +} + +impl<'a, T, U> Sub for Mut<'a, T> +where + T: Sub, + T: Copy, +{ + type Output = T; + + fn sub(self, rhs: U) -> Self::Output { + *self.value - rhs + } +} + +impl<'a, T, U, V> Index for Mut<'a, T> +where + T: Index, +{ + type Output = V; + + fn index(&self, index: U) -> &Self::Output { + &self.as_ref()[index] + } +} + +impl<'a, T, U, V> IndexMut for Mut<'a, T> +where + T: IndexMut, +{ + fn index_mut(&mut self, index: U) -> &mut Self::Output { + &mut self.as_mut()[index] + } +} + +impl<'a, T, U> Neg for Mut<'a, T> +where + T: Neg + Copy, +{ + type Output = U; + + fn neg(self) -> Self::Output { + -*self + } +} + +impl<'a, T, U> Not for Mut<'a, T> +where + T: Not + Copy, +{ + type Output = U; + + fn not(self) -> Self::Output { + !*self + } +} + change_detection_impl!(Mut<'a, T>, T,); impl_into_inner!(Mut<'a, T>, T,); impl_debug!(Mut<'a, T>,); From c8ee99b6db519cbdd52ae4c537d5a44770614ddd Mon Sep 17 00:00:00 2001 From: Ickshonpe Date: Sun, 6 Feb 2022 22:23:29 +0000 Subject: [PATCH 6/6] Revert " Implements std::ops operator traits for Mut." This reverts commit d87f9979ad18f19a999e4c0893573cb48f4805d2. --- crates/bevy_ecs/src/change_detection.rs | 241 +----------------------- 1 file changed, 1 insertion(+), 240 deletions(-) diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 355e1796c20a2..369d9ecfab486 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -3,11 +3,7 @@ use crate::{component::ComponentTicks, system::Resource}; #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; -use std::ops::{ - Add, AddAssign, BitAnd, BitOr, BitOrAssign, BitXor, Deref, DerefMut, Div, DivAssign, Index, - IndexMut, Mul, MulAssign, Neg, Not, RangeBounds, Rem, RemAssign, Shl, ShlAssign, Shr, - ShrAssign, Sub, SubAssign, -}; +use std::ops::{Deref, DerefMut}; /// Types that implement reliable change detection. /// @@ -188,241 +184,6 @@ pub struct Mut<'a, T> { pub(crate) ticks: Ticks<'a>, } -impl<'a, T, U, V> Add for Mut<'a, T> -where - T: Add + Copy, -{ - type Output = V; - - fn add(self, rhs: U) -> Self::Output { - *self.value + rhs - } -} - -impl<'a, T, U> AddAssign for Mut<'a, T> -where - T: AddAssign, -{ - fn add_assign(&mut self, rhs: U) { - *self.value += rhs; - } -} - -impl<'a, T, U, V> BitAnd for Mut<'a, T> -where - T: BitAnd + Copy, -{ - type Output = V; - - fn bitand(self, rhs: U) -> Self::Output { - *self & rhs - } -} - -impl<'a, T, U, V> BitOr for Mut<'a, T> -where - T: BitOr + Copy, -{ - type Output = V; - - fn bitor(self, rhs: U) -> Self::Output { - *self | rhs - } -} - -impl<'a, T, U> BitOrAssign for Mut<'a, T> -where - T: BitOrAssign, -{ - fn bitor_assign(&mut self, rhs: U) { - *self.value |= rhs; - } -} - -impl<'a, T, U, V> BitXor for Mut<'a, T> -where - T: BitXor + Copy, -{ - type Output = V; - - fn bitxor(self, rhs: U) -> Self::Output { - *self ^ rhs - } -} - -impl<'a, T, U> Div for Mut<'a, T> -where - T: Div + Copy, -{ - type Output = T; - - fn div(self, rhs: U) -> Self::Output { - *self.value / rhs - } -} - -impl<'a, T, U> DivAssign for Mut<'a, T> -where - T: DivAssign, -{ - fn div_assign(&mut self, rhs: U) { - *self.value /= rhs; - } -} - -impl<'a, T, U> Mul for Mut<'a, T> -where - T: Mul + Copy, -{ - type Output = T; - - fn mul(self, rhs: U) -> Self::Output { - *self.value * rhs - } -} - -impl<'a, T, U> MulAssign for Mut<'a, T> -where - T: MulAssign, -{ - fn mul_assign(&mut self, rhs: U) { - *self.value *= rhs; - } -} - -impl<'a, T> RangeBounds for Mut<'a, T> -where - T: RangeBounds, -{ - fn start_bound(&self) -> std::ops::Bound<&T> { - self.as_ref().start_bound() - } - - fn end_bound(&self) -> std::ops::Bound<&T> { - self.as_ref().end_bound() - } -} - -impl<'a, T, U> Rem for Mut<'a, T> -where - T: Rem + Copy, -{ - type Output = U; - fn rem(self, rhs: T) -> Self::Output { - *self % rhs - } -} - -impl<'a, T, U> RemAssign for Mut<'a, T> -where - T: RemAssign, -{ - fn rem_assign(&mut self, rhs: U) { - *self.value %= rhs; - } -} - -impl<'a, T, U> Shl for Mut<'a, T> -where - T: Shl + Copy, -{ - type Output = U; - fn shl(self, rhs: T) -> Self::Output { - *self << rhs - } -} - -impl<'a, T, U> ShlAssign for Mut<'a, T> -where - T: ShlAssign, -{ - fn shl_assign(&mut self, rhs: U) { - *self.value <<= rhs; - } -} - -impl<'a, T, U> Shr for Mut<'a, T> -where - T: Shr + Copy, -{ - type Output = U; - fn shr(self, rhs: T) -> Self::Output { - *self >> rhs - } -} - -impl<'a, T, U> ShrAssign for Mut<'a, T> -where - T: ShrAssign, -{ - fn shr_assign(&mut self, rhs: U) { - *self.value >>= rhs; - } -} - -impl<'a, T, U> SubAssign for Mut<'a, T> -where - T: SubAssign, -{ - fn sub_assign(&mut self, rhs: U) { - *self.value -= rhs; - } -} - -impl<'a, T, U> Sub for Mut<'a, T> -where - T: Sub, - T: Copy, -{ - type Output = T; - - fn sub(self, rhs: U) -> Self::Output { - *self.value - rhs - } -} - -impl<'a, T, U, V> Index for Mut<'a, T> -where - T: Index, -{ - type Output = V; - - fn index(&self, index: U) -> &Self::Output { - &self.as_ref()[index] - } -} - -impl<'a, T, U, V> IndexMut for Mut<'a, T> -where - T: IndexMut, -{ - fn index_mut(&mut self, index: U) -> &mut Self::Output { - &mut self.as_mut()[index] - } -} - -impl<'a, T, U> Neg for Mut<'a, T> -where - T: Neg + Copy, -{ - type Output = U; - - fn neg(self) -> Self::Output { - -*self - } -} - -impl<'a, T, U> Not for Mut<'a, T> -where - T: Not + Copy, -{ - type Output = U; - - fn not(self) -> Self::Output { - !*self - } -} - change_detection_impl!(Mut<'a, T>, T,); impl_into_inner!(Mut<'a, T>, T,); impl_debug!(Mut<'a, T>,);