Skip to content

Unconditional Visibility::Visible variant #1

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

Closed
wants to merge 4 commits into from
Closed
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
122 changes: 96 additions & 26 deletions crates/bevy_render/src/view/visibility/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ 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 @@ -28,9 +27,6 @@ use crate::{
/// 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.
///
/// 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 enum Visibility {
Expand All @@ -41,6 +37,10 @@ pub enum Visibility {
/// 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,
/// An entity with `Visibility::Visible` will be unconditionally visible, regardless of whether
/// the [`Parent`] entity is hidden or not. Visibility will also be propagated to any
/// [`Children`] set to `Visibility::Inherited`.
Visible,
}

impl Default for Visibility {
Expand All @@ -49,32 +49,20 @@ impl Default for Visibility {
}
}

impl Not for Visibility {
type Output = Visibility;

#[inline]
fn not(self) -> Visibility {
match self {
Visibility::Inherited => Visibility::Hidden,
Visibility::Hidden => Visibility::Inherited,
}
}
}

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.
///
/// Calling `toggle` on the unconditional Visible value will turn it into Hidden as expected,
/// however subsequent calls of `toggle` will only alternate between Inherited and Hidden.
#[inline]
pub fn toggle(&mut self) {
*self = !*self;
*self = match self {
Visibility::Inherited | Visibility::Visible => Visibility::Hidden,
Visibility::Hidden => Visibility::Inherited,
}
}

/// Set the visibility to either Inherited or Hidden using a boolean expression.
/// Set the visibility to either Inherited (true) or Hidden (false) using a boolean expression.
#[inline]
pub fn set(&mut self, inherited: bool) {
*self = if inherited {
Expand Down Expand Up @@ -302,7 +290,9 @@ 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_inherited();
// Setting `Visibility::Inherited` on the root entity is the same as setting `Visibility::Visible`.
computed_visibility.is_visible_in_hierarchy =
*visibility == Visibility::Inherited || *visibility == Visibility::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;
if let Some(children) = children {
Expand Down Expand Up @@ -335,7 +325,9 @@ 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_inherited() && parent_visible;
computed_visibility.is_visible_in_hierarchy = (parent_visible
&& *visibility == Visibility::Inherited)
|| *visibility == Visibility::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 @@ -576,6 +568,84 @@ mod test {
);
}

#[test]
fn visibility_propagation_unconditional_visible() {
let mut app = App::new();
app.add_system(visibility_propagate_system);

let root1 = app
.world
.spawn((Visibility::Visible, ComputedVisibility::default()))
.id();
let root1_child1 = app
.world
.spawn((Visibility::Inherited, ComputedVisibility::default()))
.id();
let root1_child2 = app
.world
.spawn((Visibility::Hidden, ComputedVisibility::default()))
.id();
let root1_child1_grandchild1 = app
.world
.spawn((Visibility::Visible, ComputedVisibility::default()))
.id();
let root1_child2_grandchild1 = app
.world
.spawn((Visibility::Visible, ComputedVisibility::default()))
.id();

let root2 = app
.world
.spawn((Visibility::Inherited, ComputedVisibility::default()))
.id();
let root3 = app
.world
.spawn((Visibility::Hidden, ComputedVisibility::default()))
.id();

app.world
.entity_mut(root1)
.push_children(&[root1_child1, root1_child2]);
app.world
.entity_mut(root1_child1)
.push_children(&[root1_child1_grandchild1]);
app.world
.entity_mut(root1_child2)
.push_children(&[root1_child2_grandchild1]);

app.update();

let is_visible = |e: Entity| {
app.world
.entity(e)
.get::<ComputedVisibility>()
.unwrap()
.is_visible_in_hierarchy
};
assert!(
is_visible(root1),
"an unconditionally visible root is visible"
);
assert!(
is_visible(root1_child1),
"an inheriting child of an unconditionally visible parent is visible"
);
assert!(
!is_visible(root1_child2),
"a hidden child on an unconditionally visible parent is hidden"
);
assert!(
is_visible(root1_child1_grandchild1),
"an unconditionally visible child of an inheriting parent is visible"
);
assert!(
is_visible(root1_child2_grandchild1),
"an unconditionally visible child of a hidden parent is visible"
);
assert!(is_visible(root2), "an inheriting root in visible");
assert!(!is_visible(root3), "a hidden root is hidden");
}

#[test]
fn ensure_visibility_enum_size() {
use std::mem;
Expand Down