Skip to content
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

Turn the Visibility struct into an enum #6271

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion crates/bevy_gltf/src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_render/src/spatial_bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}

Expand Down
92 changes: 61 additions & 31 deletions crates/bevy_render/src/view/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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 {
ickk marked this conversation as resolved.
Show resolved Hide resolved
/// 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,
ickk marked this conversation as resolved.
Show resolved Hide resolved
/// 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
}
}
}

Expand All @@ -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,
};
Expand Down Expand Up @@ -271,7 +302,7 @@ fn visibility_propagate_system(
children_query: Query<&Children, (With<Parent>, With<Visibility>, With<ComputedVisibility>)>,
) {
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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -433,21 +464,15 @@ mod test {

let root1 = app
.world
.spawn((
Visibility { is_visible: false },
ComputedVisibility::default(),
))
.spawn((Visibility::Hidden, ComputedVisibility::default()))
.id();
let root1_child1 = app
.world
.spawn((Visibility::default(), ComputedVisibility::default()))
.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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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::<Visibility>());
assert_eq!(1, mem::size_of::<Option<Visibility>>());
assert_eq!(1, mem::size_of::<Option<Option<Visibility>>>());
}
}
2 changes: 1 addition & 1 deletion examples/2d/mesh2d_manual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ fn star(
// The `Handle<Mesh>` 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
Expand Down
2 changes: 1 addition & 1 deletion examples/animation/animated_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
))
Expand Down
2 changes: 1 addition & 1 deletion examples/shader/shader_instancing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn main() {
fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
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)))
Expand Down
2 changes: 1 addition & 1 deletion examples/stress_tests/many_foxes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
))
Expand Down