Path: blob/main/crates/bevy_camera/src/visibility/render_layers.rs
6599 views
use bevy_ecs::prelude::{Component, ReflectComponent};1use bevy_reflect::{std_traits::ReflectDefault, Reflect};2use smallvec::SmallVec;34pub const DEFAULT_LAYERS: &RenderLayers = &RenderLayers::layer(0);56/// An identifier for a rendering layer.7pub type Layer = usize;89/// Defines which rendering layers an entity belongs to.10///11/// A camera renders an entity only when their render layers intersect.12///13/// The [`Default`] instance of `RenderLayers` contains layer `0`, the first layer. Entities14/// without this component also belong to layer `0`.15///16/// An empty `RenderLayers` makes the entity invisible.17#[derive(Component, Clone, Reflect, PartialEq, Eq, PartialOrd, Ord)]18#[reflect(Component, Default, PartialEq, Debug, Clone)]19pub struct RenderLayers(SmallVec<[u64; INLINE_BLOCKS]>);2021/// The number of memory blocks stored inline22const INLINE_BLOCKS: usize = 1;2324impl Default for &RenderLayers {25fn default() -> Self {26DEFAULT_LAYERS27}28}2930impl core::fmt::Debug for RenderLayers {31fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {32f.debug_tuple("RenderLayers")33.field(&self.iter().collect::<Vec<_>>())34.finish()35}36}3738impl FromIterator<Layer> for RenderLayers {39fn from_iter<T: IntoIterator<Item = Layer>>(i: T) -> Self {40i.into_iter().fold(Self::none(), RenderLayers::with)41}42}4344impl Default for RenderLayers {45/// By default, this structure includes layer `0`, which represents the first layer.46///47/// This is distinct from [`RenderLayers::none`], which doesn't belong to any layers.48fn default() -> Self {49const { Self::layer(0) }50}51}5253impl RenderLayers {54/// Create a new `RenderLayers` belonging to the given layer.55///56/// This `const` constructor is limited to `size_of::<usize>()` layers.57/// If you need to support an arbitrary number of layers, use [`with`](RenderLayers::with)58/// or [`from_layers`](RenderLayers::from_layers).59pub const fn layer(n: Layer) -> Self {60let (buffer_index, bit) = Self::layer_info(n);61assert!(62buffer_index < INLINE_BLOCKS,63"layer is out of bounds for const construction"64);65let mut buffer = [0; INLINE_BLOCKS];66buffer[buffer_index] = bit;67RenderLayers(SmallVec::from_const(buffer))68}6970/// Create a new `RenderLayers` that belongs to no layers.71///72/// This is distinct from [`RenderLayers::default`], which belongs to the first layer.73pub const fn none() -> Self {74RenderLayers(SmallVec::from_const([0; INLINE_BLOCKS]))75}7677/// Create a `RenderLayers` from a list of layers.78pub fn from_layers(layers: &[Layer]) -> Self {79layers.iter().copied().collect()80}8182/// Add the given layer.83///84/// This may be called multiple times to allow an entity to belong85/// to multiple rendering layers.86#[must_use]87pub fn with(mut self, layer: Layer) -> Self {88let (buffer_index, bit) = Self::layer_info(layer);89self.extend_buffer(buffer_index + 1);90self.0[buffer_index] |= bit;91self92}9394/// Removes the given rendering layer.95#[must_use]96pub fn without(mut self, layer: Layer) -> Self {97let (buffer_index, bit) = Self::layer_info(layer);98if buffer_index < self.0.len() {99self.0[buffer_index] &= !bit;100// Drop trailing zero memory blocks.101// NOTE: This is not just an optimization, it is necessary for the derived PartialEq impl to be correct.102if buffer_index == self.0.len() - 1 {103self = self.shrink();104}105}106self107}108109/// Get an iterator of the layers.110pub fn iter(&self) -> impl Iterator<Item = Layer> + '_ {111self.0.iter().copied().zip(0..).flat_map(Self::iter_layers)112}113114/// Determine if a `RenderLayers` intersects another.115///116/// `RenderLayers`s intersect if they share any common layers.117///118/// A `RenderLayers` with no layers will not match any other119/// `RenderLayers`, even another with no layers.120pub fn intersects(&self, other: &RenderLayers) -> bool {121// Check for the common case where the view layer and entity layer122// both point towards our default layer.123if self.0.as_ptr() == other.0.as_ptr() {124return true;125}126127for (self_layer, other_layer) in self.0.iter().zip(other.0.iter()) {128if (*self_layer & *other_layer) != 0 {129return true;130}131}132133false134}135136/// Get the bitmask representation of the contained layers.137pub fn bits(&self) -> &[u64] {138self.0.as_slice()139}140141const fn layer_info(layer: usize) -> (usize, u64) {142let buffer_index = layer / 64;143let bit_index = layer % 64;144let bit = 1u64 << bit_index;145146(buffer_index, bit)147}148149fn extend_buffer(&mut self, other_len: usize) {150let new_size = core::cmp::max(self.0.len(), other_len);151self.0.reserve_exact(new_size - self.0.len());152self.0.resize(new_size, 0u64);153}154155fn iter_layers(buffer_and_offset: (u64, usize)) -> impl Iterator<Item = Layer> + 'static {156let (mut buffer, mut layer) = buffer_and_offset;157layer *= 64;158core::iter::from_fn(move || {159if buffer == 0 {160return None;161}162let next = buffer.trailing_zeros() + 1;163buffer = buffer.checked_shr(next).unwrap_or(0);164layer += next as usize;165Some(layer - 1)166})167}168169/// Returns the set of [layers](Layer) shared by two instances of [`RenderLayers`].170///171/// This corresponds to the `self & other` operation.172pub fn intersection(&self, other: &Self) -> Self {173self.combine_blocks(other, |a, b| a & b).shrink()174}175176/// Returns all [layers](Layer) included in either instance of [`RenderLayers`].177///178/// This corresponds to the `self | other` operation.179pub fn union(&self, other: &Self) -> Self {180self.combine_blocks(other, |a, b| a | b) // doesn't need to be shrunk, if the inputs are nonzero then the result will be too181}182183/// Returns all [layers](Layer) included in exactly one of the instances of [`RenderLayers`].184///185/// This corresponds to the "exclusive or" (XOR) operation: `self ^ other`.186pub fn symmetric_difference(&self, other: &Self) -> Self {187self.combine_blocks(other, |a, b| a ^ b).shrink()188}189190/// Deallocates any trailing-zero memory blocks from this instance191fn shrink(mut self) -> Self {192let mut any_dropped = false;193while self.0.len() > INLINE_BLOCKS && self.0.last() == Some(&0) {194self.0.pop();195any_dropped = true;196}197if any_dropped && self.0.len() <= INLINE_BLOCKS {198self.0.shrink_to_fit();199}200self201}202203/// Creates a new instance of [`RenderLayers`] by applying a function to the memory blocks204/// of self and another instance.205///206/// If the function `f` might return `0` for non-zero inputs, you should call [`Self::shrink`]207/// on the output to ensure that there are no trailing zero memory blocks that would break208/// this type's equality comparison.209fn combine_blocks(&self, other: &Self, mut f: impl FnMut(u64, u64) -> u64) -> Self {210let mut a = self.0.iter();211let mut b = other.0.iter();212let mask = core::iter::from_fn(|| {213let a = a.next().copied();214let b = b.next().copied();215if a.is_none() && b.is_none() {216return None;217}218Some(f(a.unwrap_or_default(), b.unwrap_or_default()))219});220Self(mask.collect())221}222}223224impl core::ops::BitAnd for RenderLayers {225type Output = Self;226fn bitand(self, rhs: Self) -> Self::Output {227self.intersection(&rhs)228}229}230231impl core::ops::BitOr for RenderLayers {232type Output = Self;233fn bitor(self, rhs: Self) -> Self::Output {234self.union(&rhs)235}236}237238impl core::ops::BitXor for RenderLayers {239type Output = Self;240fn bitxor(self, rhs: Self) -> Self::Output {241self.symmetric_difference(&rhs)242}243}244245#[cfg(test)]246mod rendering_mask_tests {247use super::{Layer, RenderLayers};248use smallvec::SmallVec;249250#[test]251fn rendering_mask_sanity() {252let layer_0 = RenderLayers::layer(0);253assert_eq!(layer_0.0.len(), 1, "layer 0 is one buffer");254assert_eq!(layer_0.0[0], 1, "layer 0 is mask 1");255let layer_1 = RenderLayers::layer(1);256assert_eq!(layer_1.0.len(), 1, "layer 1 is one buffer");257assert_eq!(layer_1.0[0], 2, "layer 1 is mask 2");258let layer_0_1 = RenderLayers::layer(0).with(1);259assert_eq!(layer_0_1.0.len(), 1, "layer 0 + 1 is one buffer");260assert_eq!(layer_0_1.0[0], 3, "layer 0 + 1 is mask 3");261let layer_0_1_without_0 = layer_0_1.without(0);262assert_eq!(263layer_0_1_without_0.0.len(),2641,265"layer 0 + 1 - 0 is one buffer"266);267assert_eq!(layer_0_1_without_0.0[0], 2, "layer 0 + 1 - 0 is mask 2");268let layer_0_2345 = RenderLayers::layer(0).with(2345);269assert_eq!(layer_0_2345.0.len(), 37, "layer 0 + 2345 is 37 buffers");270assert_eq!(layer_0_2345.0[0], 1, "layer 0 + 2345 is mask 1");271assert_eq!(272layer_0_2345.0[36], 2199023255552,273"layer 0 + 2345 is mask 2199023255552"274);275assert!(276layer_0_2345.intersects(&layer_0),277"layer 0 + 2345 intersects 0"278);279assert!(280RenderLayers::layer(1).intersects(&RenderLayers::layer(1)),281"layers match like layers"282);283assert!(284RenderLayers::layer(0).intersects(&RenderLayers(SmallVec::from_const([1]))),285"a layer of 0 means the mask is just 1 bit"286);287288assert!(289RenderLayers::layer(0)290.with(3)291.intersects(&RenderLayers::layer(3)),292"a mask will match another mask containing any similar layers"293);294295assert!(296RenderLayers::default().intersects(&RenderLayers::default()),297"default masks match each other"298);299300assert!(301!RenderLayers::layer(0).intersects(&RenderLayers::layer(1)),302"masks with differing layers do not match"303);304assert!(305!RenderLayers::none().intersects(&RenderLayers::none()),306"empty masks don't match"307);308assert_eq!(309RenderLayers::from_layers(&[0, 2, 16, 30])310.iter()311.collect::<Vec<_>>(),312vec![0, 2, 16, 30],313"from_layers and get_layers should roundtrip"314);315assert_eq!(316format!("{:?}", RenderLayers::from_layers(&[0, 1, 2, 3])).as_str(),317"RenderLayers([0, 1, 2, 3])",318"Debug instance shows layers"319);320assert_eq!(321RenderLayers::from_layers(&[0, 1, 2]),322<RenderLayers as FromIterator<Layer>>::from_iter(vec![0, 1, 2]),323"from_layers and from_iter are equivalent"324);325326let tricky_layers = vec![0, 5, 17, 55, 999, 1025, 1026];327let layers = RenderLayers::from_layers(&tricky_layers);328let out = layers.iter().collect::<Vec<_>>();329assert_eq!(tricky_layers, out, "tricky layers roundtrip");330}331332const MANY: RenderLayers = RenderLayers(SmallVec::from_const([u64::MAX]));333334#[test]335fn render_layer_ops() {336let a = RenderLayers::from_layers(&[2, 4, 6]);337let b = RenderLayers::from_layers(&[1, 2, 3, 4, 5]);338339assert_eq!(340a.clone() | b.clone(),341RenderLayers::from_layers(&[1, 2, 3, 4, 5, 6])342);343assert_eq!(a.clone() & b.clone(), RenderLayers::from_layers(&[2, 4]));344assert_eq!(a ^ b, RenderLayers::from_layers(&[1, 3, 5, 6]));345346assert_eq!(RenderLayers::none() & MANY, RenderLayers::none());347assert_eq!(RenderLayers::none() | MANY, MANY);348assert_eq!(RenderLayers::none() ^ MANY, MANY);349}350351#[test]352fn render_layer_shrink() {353// Since it has layers greater than 64, the instance should take up two memory blocks354let layers = RenderLayers::from_layers(&[1, 77]);355assert!(layers.0.len() == 2);356// When excluding that layer, it should drop the extra memory block357let layers = layers.without(77);358assert!(layers.0.len() == 1);359}360361#[test]362fn render_layer_iter_no_overflow() {363let layers = RenderLayers::from_layers(&[63]);364layers.iter().count();365}366}367368369