diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index ce80600020b1f..cfa4592399611 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -465,7 +465,7 @@ async fn load_gltf<'a, 'b>( let mut entity_to_skin_index_map = HashMap::new(); world - .spawn(SpatialBundle::VISIBLE_IDENTITY) + .spawn(SpatialBundle::INHERITED_IDENTITY) .with_children(|parent| { for node in scene.nodes() { let result = load_node( diff --git a/crates/bevy_render/src/spatial_bundle.rs b/crates/bevy_render/src/spatial_bundle.rs index 6eedd7cbf5992..b2d50da6097f6 100644 --- a/crates/bevy_render/src/spatial_bundle.rs +++ b/crates/bevy_render/src/spatial_bundle.rs @@ -33,22 +33,22 @@ impl SpatialBundle { pub const fn from_transform(transform: Transform) -> Self { SpatialBundle { transform, - ..Self::VISIBLE_IDENTITY + ..Self::INHERITED_IDENTITY } } /// A visible [`SpatialBundle`], with no translation, rotation, and a scale of 1 on all axes. - pub const VISIBLE_IDENTITY: Self = SpatialBundle { - visibility: Visibility::VISIBLE, - computed: ComputedVisibility::INVISIBLE, + pub const INHERITED_IDENTITY: Self = SpatialBundle { + visibility: Visibility::Inherited, + computed: ComputedVisibility::HIDDEN, transform: Transform::IDENTITY, global_transform: GlobalTransform::IDENTITY, }; /// An invisible [`SpatialBundle`], with no translation, rotation, and a scale of 1 on all axes. - pub const INVISIBLE_IDENTITY: Self = SpatialBundle { - visibility: Visibility::INVISIBLE, - ..Self::VISIBLE_IDENTITY + pub const HIDDEN_IDENTITY: Self = SpatialBundle { + visibility: Visibility::Hidden, + ..Self::INHERITED_IDENTITY }; } diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index d6979ac5e0882..9a274fb256db0 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -11,6 +11,7 @@ use bevy_reflect::Reflect; use bevy_transform::components::GlobalTransform; use bevy_transform::TransformSystem; use std::cell::Cell; +use std::ops::Not; use thread_local::ThreadLocal; use crate::{ @@ -24,33 +25,63 @@ use crate::{ /// User indication of whether an entity is visible. Propagates down the entity hierarchy. -/// If an entity is hidden in this way, all [`Children`] (and all of their children and so on) will also be hidden. +/// If an entity is hidden in this way, all [`Children`] (and all of their children and so on) who +/// are set to `Inherited` will also be hidden. /// This is done by setting the values of their [`ComputedVisibility`] component. -#[derive(Component, Clone, Reflect, Debug)] +/// +/// A root-level entity that is set to `Inherited` will be visible, and as such will cause any of +/// its [`Children`] entities which are set to `Inherited` to also be visible. +#[derive(Component, Clone, Copy, Reflect, Debug, PartialEq, Eq)] #[reflect(Component, Default)] -pub struct Visibility { - /// Indicates whether this entity is visible. Hidden values will propagate down the entity hierarchy. - /// If this entity is hidden, all of its descendants will be hidden as well. See [`Children`] and [`Parent`] for - /// hierarchy info. - pub is_visible: bool, +pub enum Visibility { + /// An entity with `Visibility::Inherited` will inherit the Visibility of its [`Parent`]. + /// + /// A root-level entity that is set to `Inherited` will be visible. + Inherited, + /// An entity with `Visibility::Hidden` will be unconditionally hidden, and will also cause any + /// of its [`Children`] which are set to `Visibility::Inherited` to also be hidden. + Hidden, } impl Default for Visibility { fn default() -> Self { - Visibility::VISIBLE + Self::Inherited } } -impl Visibility { - /// A [`Visibility`], set as visible. - pub const VISIBLE: Self = Visibility { is_visible: true }; +impl Not for Visibility { + type Output = Visibility; - /// A [`Visibility`], set as invisible. - pub const INVISIBLE: Self = Visibility { is_visible: false }; + #[inline] + fn not(self) -> Visibility { + match self { + Visibility::Inherited => Visibility::Hidden, + Visibility::Hidden => Visibility::Inherited, + } + } +} - /// Toggle the visibility. +impl Visibility { + /// Whether this entity is Inherited. + #[inline] + pub const fn is_inherited(&self) -> bool { + matches!(self, Self::Inherited) + } + + /// Toggle the visibility state between Inherited and Hidden. + #[inline] pub fn toggle(&mut self) { - self.is_visible = !self.is_visible; + *self = !*self; + } + + /// Set the visibility to either Inherited or Hidden using a boolean expression. + #[inline] + pub fn set(&mut self, inherited: bool) { + *self = if inherited { + Self::Inherited + } else { + Self::Hidden + } } } @@ -64,13 +95,13 @@ pub struct ComputedVisibility { impl Default for ComputedVisibility { fn default() -> Self { - Self::INVISIBLE + Self::HIDDEN } } impl ComputedVisibility { /// A [`ComputedVisibility`], set as invisible. - pub const INVISIBLE: Self = ComputedVisibility { + pub const HIDDEN: Self = ComputedVisibility { is_visible_in_hierarchy: false, is_visible_in_view: false, }; @@ -271,7 +302,7 @@ fn visibility_propagate_system( children_query: Query<&Children, (With, With, With)>, ) { for (children, visibility, mut computed_visibility, entity) in root_query.iter_mut() { - computed_visibility.is_visible_in_hierarchy = visibility.is_visible; + computed_visibility.is_visible_in_hierarchy = visibility.is_inherited(); // reset "view" visibility here ... if this entity should be drawn a future system should set this to true computed_visibility.is_visible_in_view = false; if let Some(children) = children { @@ -304,7 +335,7 @@ fn propagate_recursive( child_parent.get(), expected_parent, "Malformed hierarchy. This probably means that your hierarchy has been improperly maintained, or contains a cycle" ); - computed_visibility.is_visible_in_hierarchy = visibility.is_visible && parent_visible; + computed_visibility.is_visible_in_hierarchy = visibility.is_inherited() && parent_visible; // reset "view" visibility here ... if this entity should be drawn a future system should set this to true computed_visibility.is_visible_in_view = false; computed_visibility.is_visible_in_hierarchy @@ -433,10 +464,7 @@ mod test { let root1 = app .world - .spawn(( - Visibility { is_visible: false }, - ComputedVisibility::default(), - )) + .spawn((Visibility::Hidden, ComputedVisibility::default())) .id(); let root1_child1 = app .world @@ -444,10 +472,7 @@ mod test { .id(); let root1_child2 = app .world - .spawn(( - Visibility { is_visible: false }, - ComputedVisibility::default(), - )) + .spawn((Visibility::Hidden, ComputedVisibility::default())) .id(); let root1_child1_grandchild1 = app .world @@ -478,10 +503,7 @@ mod test { .id(); let root2_child2 = app .world - .spawn(( - Visibility { is_visible: false }, - ComputedVisibility::default(), - )) + .spawn((Visibility::Hidden, ComputedVisibility::default())) .id(); let root2_child1_grandchild1 = app .world @@ -553,4 +575,12 @@ mod test { "child's invisibility propagates down to grandchild" ); } + + #[test] + fn ensure_visibility_enum_size() { + use std::mem; + assert_eq!(1, mem::size_of::()); + assert_eq!(1, mem::size_of::>()); + assert_eq!(1, mem::size_of::>>()); + } } diff --git a/examples/2d/mesh2d_manual.rs b/examples/2d/mesh2d_manual.rs index 5eb72f3a19d88..602ce568efd32 100644 --- a/examples/2d/mesh2d_manual.rs +++ b/examples/2d/mesh2d_manual.rs @@ -103,7 +103,7 @@ fn star( // The `Handle` needs to be wrapped in a `Mesh2dHandle` to use 2d rendering instead of 3d Mesh2dHandle(meshes.add(star)), // This bundle's components are needed for something to be rendered - SpatialBundle::VISIBLE_IDENTITY, + SpatialBundle::INHERITED_IDENTITY, )); // Spawn the camera diff --git a/examples/animation/animated_transform.rs b/examples/animation/animated_transform.rs index 19f284aa02519..cf82eb4e72c7e 100644 --- a/examples/animation/animated_transform.rs +++ b/examples/animation/animated_transform.rs @@ -129,7 +129,7 @@ fn setup( .with_children(|p| { // This entity is just used for animation, but doesn't display anything p.spawn(( - SpatialBundle::VISIBLE_IDENTITY, + SpatialBundle::INHERITED_IDENTITY, // Add the Name component orbit_controller, )) diff --git a/examples/shader/shader_instancing.rs b/examples/shader/shader_instancing.rs index 71e68566b40e5..4012473a5b879 100644 --- a/examples/shader/shader_instancing.rs +++ b/examples/shader/shader_instancing.rs @@ -32,7 +32,7 @@ fn main() { fn setup(mut commands: Commands, mut meshes: ResMut>) { commands.spawn(( meshes.add(Mesh::from(shape::Cube { size: 0.5 })), - SpatialBundle::VISIBLE_IDENTITY, + SpatialBundle::INHERITED_IDENTITY, InstanceMaterialData( (1..=10) .flat_map(|x| (1..=10).map(move |y| (x as f32 / 10.0, y as f32 / 10.0))) diff --git a/examples/stress_tests/many_foxes.rs b/examples/stress_tests/many_foxes.rs index d67d05e5b50e0..b9ec2314e7752 100644 --- a/examples/stress_tests/many_foxes.rs +++ b/examples/stress_tests/many_foxes.rs @@ -111,7 +111,7 @@ fn setup( let (base_rotation, ring_direction) = ring_directions[ring_index % 2]; let ring_parent = commands .spawn(( - SpatialBundle::VISIBLE_IDENTITY, + SpatialBundle::INHERITED_IDENTITY, ring_direction, Ring { radius }, ))