bevy_render/view/visibility/
render_layers.rs

1use bevy_ecs::prelude::{Component, ReflectComponent};
2use bevy_reflect::std_traits::ReflectDefault;
3use bevy_reflect::Reflect;
4use smallvec::SmallVec;
5
6pub const DEFAULT_LAYERS: &RenderLayers = &RenderLayers::layer(0);
7
8/// An identifier for a rendering layer.
9pub type Layer = usize;
10
11/// Describes which rendering layers an entity belongs to.
12///
13/// Cameras with this component will only render entities with intersecting
14/// layers.
15///
16/// Entities may belong to one or more layers, or no layer at all.
17///
18/// The [`Default`] instance of `RenderLayers` contains layer `0`, the first layer.
19///
20/// An entity with this component without any layers is invisible.
21///
22/// Entities without this component belong to layer `0`.
23#[derive(Component, Clone, Reflect, PartialEq, Eq, PartialOrd, Ord)]
24#[reflect(Component, Default, PartialEq)]
25pub struct RenderLayers(SmallVec<[u64; INLINE_BLOCKS]>);
26
27/// The number of memory blocks stored inline
28const INLINE_BLOCKS: usize = 1;
29
30impl Default for &RenderLayers {
31    fn default() -> Self {
32        DEFAULT_LAYERS
33    }
34}
35
36impl std::fmt::Debug for RenderLayers {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        f.debug_tuple("RenderLayers")
39            .field(&self.iter().collect::<Vec<_>>())
40            .finish()
41    }
42}
43
44impl FromIterator<Layer> for RenderLayers {
45    fn from_iter<T: IntoIterator<Item = Layer>>(i: T) -> Self {
46        i.into_iter().fold(Self::none(), |mask, g| mask.with(g))
47    }
48}
49
50impl Default for RenderLayers {
51    /// By default, this structure includes layer `0`, which represents the first layer.
52    ///
53    /// This is distinct from [`RenderLayers::none`], which doesn't belong to any layers.
54    fn default() -> Self {
55        const { Self::layer(0) }
56    }
57}
58
59impl RenderLayers {
60    /// Create a new `RenderLayers` belonging to the given layer.
61    pub const fn layer(n: Layer) -> Self {
62        let (buffer_index, bit) = Self::layer_info(n);
63        assert!(
64            buffer_index < INLINE_BLOCKS,
65            "layer is out of bounds for const construction"
66        );
67        let mut buffer = [0; INLINE_BLOCKS];
68        buffer[buffer_index] = bit;
69        RenderLayers(SmallVec::from_const(buffer))
70    }
71
72    /// Create a new `RenderLayers` that belongs to no layers.
73    ///
74    /// This is distinct from [`RenderLayers::default`], which belongs to the first layer.
75    pub const fn none() -> Self {
76        RenderLayers(SmallVec::from_const([0; INLINE_BLOCKS]))
77    }
78
79    /// Create a `RenderLayers` from a list of layers.
80    pub fn from_layers(layers: &[Layer]) -> Self {
81        layers.iter().copied().collect()
82    }
83
84    /// Add the given layer.
85    ///
86    /// This may be called multiple times to allow an entity to belong
87    /// to multiple rendering layers.
88    #[must_use]
89    pub fn with(mut self, layer: Layer) -> Self {
90        let (buffer_index, bit) = Self::layer_info(layer);
91        self.extend_buffer(buffer_index + 1);
92        self.0[buffer_index] |= bit;
93        self
94    }
95
96    /// Removes the given rendering layer.
97    #[must_use]
98    pub fn without(mut self, layer: Layer) -> Self {
99        let (buffer_index, bit) = Self::layer_info(layer);
100        if buffer_index < self.0.len() {
101            self.0[buffer_index] &= !bit;
102            // Drop trailing zero memory blocks.
103            // NOTE: This is not just an optimization, it is necessary for the derived PartialEq impl to be correct.
104            if buffer_index == self.0.len() - 1 {
105                self = self.shrink();
106            }
107        }
108        self
109    }
110
111    /// Get an iterator of the layers.
112    pub fn iter(&self) -> impl Iterator<Item = Layer> + '_ {
113        self.0.iter().copied().zip(0..).flat_map(Self::iter_layers)
114    }
115
116    /// Determine if a `RenderLayers` intersects another.
117    ///
118    /// `RenderLayers`s intersect if they share any common layers.
119    ///
120    /// A `RenderLayers` with no layers will not match any other
121    /// `RenderLayers`, even another with no layers.
122    pub fn intersects(&self, other: &RenderLayers) -> bool {
123        // Check for the common case where the view layer and entity layer
124        // both point towards our default layer.
125        if self.0.as_ptr() == other.0.as_ptr() {
126            return true;
127        }
128
129        for (self_layer, other_layer) in self.0.iter().zip(other.0.iter()) {
130            if (*self_layer & *other_layer) != 0 {
131                return true;
132            }
133        }
134
135        false
136    }
137
138    /// get the bitmask representation of the contained layers
139    pub fn bits(&self) -> &[u64] {
140        self.0.as_slice()
141    }
142
143    const fn layer_info(layer: usize) -> (usize, u64) {
144        let buffer_index = layer / 64;
145        let bit_index = layer % 64;
146        let bit = 1u64 << bit_index;
147
148        (buffer_index, bit)
149    }
150
151    fn extend_buffer(&mut self, other_len: usize) {
152        let new_size = std::cmp::max(self.0.len(), other_len);
153        self.0.reserve_exact(new_size - self.0.len());
154        self.0.resize(new_size, 0u64);
155    }
156
157    fn iter_layers(buffer_and_offset: (u64, usize)) -> impl Iterator<Item = Layer> + 'static {
158        let (mut buffer, mut layer) = buffer_and_offset;
159        layer *= 64;
160        std::iter::from_fn(move || {
161            if buffer == 0 {
162                return None;
163            }
164            let next = buffer.trailing_zeros() + 1;
165            buffer = buffer.checked_shr(next).unwrap_or(0);
166            layer += next as usize;
167            Some(layer - 1)
168        })
169    }
170
171    /// Returns the set of [layers](Layer) shared by two instances of [`RenderLayers`].
172    ///
173    /// This corresponds to the `self & other` operation.
174    pub fn intersection(&self, other: &Self) -> Self {
175        self.combine_blocks(other, |a, b| a & b).shrink()
176    }
177
178    /// Returns all [layers](Layer) included in either instance of [`RenderLayers`].
179    ///
180    /// This corresponds to the `self | other` operation.
181    pub fn union(&self, other: &Self) -> Self {
182        self.combine_blocks(other, |a, b| a | b) // doesn't need to be shrunk, if the inputs are nonzero then the result will be too
183    }
184
185    /// Returns all [layers](Layer) included in exactly one of the instances of [`RenderLayers`].
186    ///
187    /// This corresponds to the "exclusive or" (XOR) operation: `self ^ other`.
188    pub fn symmetric_difference(&self, other: &Self) -> Self {
189        self.combine_blocks(other, |a, b| a ^ b).shrink()
190    }
191
192    /// Deallocates any trailing-zero memory blocks from this instance
193    fn shrink(mut self) -> Self {
194        let mut any_dropped = false;
195        while self.0.len() > INLINE_BLOCKS && self.0.last() == Some(&0) {
196            self.0.pop();
197            any_dropped = true;
198        }
199        if any_dropped && self.0.len() <= INLINE_BLOCKS {
200            self.0.shrink_to_fit();
201        }
202        self
203    }
204
205    /// Creates a new instance of [`RenderLayers`] by applying a function to the memory blocks
206    /// of self and another instance.
207    ///
208    /// If the function `f` might return `0` for non-zero inputs, you should call [`Self::shrink`]
209    /// on the output to ensure that there are no trailing zero memory blocks that would break
210    /// this type's equality comparison.
211    fn combine_blocks(&self, other: &Self, mut f: impl FnMut(u64, u64) -> u64) -> Self {
212        let mut a = self.0.iter();
213        let mut b = other.0.iter();
214        let mask = std::iter::from_fn(|| {
215            let a = a.next().copied();
216            let b = b.next().copied();
217            if a.is_none() && b.is_none() {
218                return None;
219            }
220            Some(f(a.unwrap_or_default(), b.unwrap_or_default()))
221        });
222        Self(mask.collect())
223    }
224}
225
226impl std::ops::BitAnd for RenderLayers {
227    type Output = Self;
228    fn bitand(self, rhs: Self) -> Self::Output {
229        self.intersection(&rhs)
230    }
231}
232
233impl std::ops::BitOr for RenderLayers {
234    type Output = Self;
235    fn bitor(self, rhs: Self) -> Self::Output {
236        self.union(&rhs)
237    }
238}
239
240impl std::ops::BitXor for RenderLayers {
241    type Output = Self;
242    fn bitxor(self, rhs: Self) -> Self::Output {
243        self.symmetric_difference(&rhs)
244    }
245}
246
247#[cfg(test)]
248mod rendering_mask_tests {
249    use super::{Layer, RenderLayers};
250    use smallvec::SmallVec;
251
252    #[test]
253    fn rendering_mask_sanity() {
254        let layer_0 = RenderLayers::layer(0);
255        assert_eq!(layer_0.0.len(), 1, "layer 0 is one buffer");
256        assert_eq!(layer_0.0[0], 1, "layer 0 is mask 1");
257        let layer_1 = RenderLayers::layer(1);
258        assert_eq!(layer_1.0.len(), 1, "layer 1 is one buffer");
259        assert_eq!(layer_1.0[0], 2, "layer 1 is mask 2");
260        let layer_0_1 = RenderLayers::layer(0).with(1);
261        assert_eq!(layer_0_1.0.len(), 1, "layer 0 + 1 is one buffer");
262        assert_eq!(layer_0_1.0[0], 3, "layer 0 + 1 is mask 3");
263        let layer_0_1_without_0 = layer_0_1.without(0);
264        assert_eq!(
265            layer_0_1_without_0.0.len(),
266            1,
267            "layer 0 + 1 - 0 is one buffer"
268        );
269        assert_eq!(layer_0_1_without_0.0[0], 2, "layer 0 + 1 - 0 is mask 2");
270        let layer_0_2345 = RenderLayers::layer(0).with(2345);
271        assert_eq!(layer_0_2345.0.len(), 37, "layer 0 + 2345 is 37 buffers");
272        assert_eq!(layer_0_2345.0[0], 1, "layer 0 + 2345 is mask 1");
273        assert_eq!(
274            layer_0_2345.0[36], 2199023255552,
275            "layer 0 + 2345 is mask 2199023255552"
276        );
277        assert!(
278            layer_0_2345.intersects(&layer_0),
279            "layer 0 + 2345 intersects 0"
280        );
281        assert!(
282            RenderLayers::layer(1).intersects(&RenderLayers::layer(1)),
283            "layers match like layers"
284        );
285        assert!(
286            RenderLayers::layer(0).intersects(&RenderLayers(SmallVec::from_const([1]))),
287            "a layer of 0 means the mask is just 1 bit"
288        );
289
290        assert!(
291            RenderLayers::layer(0)
292                .with(3)
293                .intersects(&RenderLayers::layer(3)),
294            "a mask will match another mask containing any similar layers"
295        );
296
297        assert!(
298            RenderLayers::default().intersects(&RenderLayers::default()),
299            "default masks match each other"
300        );
301
302        assert!(
303            !RenderLayers::layer(0).intersects(&RenderLayers::layer(1)),
304            "masks with differing layers do not match"
305        );
306        assert!(
307            !RenderLayers::none().intersects(&RenderLayers::none()),
308            "empty masks don't match"
309        );
310        assert_eq!(
311            RenderLayers::from_layers(&[0, 2, 16, 30])
312                .iter()
313                .collect::<Vec<_>>(),
314            vec![0, 2, 16, 30],
315            "from_layers and get_layers should roundtrip"
316        );
317        assert_eq!(
318            format!("{:?}", RenderLayers::from_layers(&[0, 1, 2, 3])).as_str(),
319            "RenderLayers([0, 1, 2, 3])",
320            "Debug instance shows layers"
321        );
322        assert_eq!(
323            RenderLayers::from_layers(&[0, 1, 2]),
324            <RenderLayers as FromIterator<Layer>>::from_iter(vec![0, 1, 2]),
325            "from_layers and from_iter are equivalent"
326        );
327
328        let tricky_layers = vec![0, 5, 17, 55, 999, 1025, 1026];
329        let layers = RenderLayers::from_layers(&tricky_layers);
330        let out = layers.iter().collect::<Vec<_>>();
331        assert_eq!(tricky_layers, out, "tricky layers roundtrip");
332    }
333
334    const MANY: RenderLayers = RenderLayers(SmallVec::from_const([u64::MAX]));
335
336    #[test]
337    fn render_layer_ops() {
338        let a = RenderLayers::from_layers(&[2, 4, 6]);
339        let b = RenderLayers::from_layers(&[1, 2, 3, 4, 5]);
340
341        assert_eq!(
342            a.clone() | b.clone(),
343            RenderLayers::from_layers(&[1, 2, 3, 4, 5, 6])
344        );
345        assert_eq!(a.clone() & b.clone(), RenderLayers::from_layers(&[2, 4]));
346        assert_eq!(a ^ b, RenderLayers::from_layers(&[1, 3, 5, 6]));
347
348        assert_eq!(RenderLayers::none() & MANY, RenderLayers::none());
349        assert_eq!(RenderLayers::none() | MANY, MANY);
350        assert_eq!(RenderLayers::none() ^ MANY, MANY);
351    }
352
353    #[test]
354    fn render_layer_shrink() {
355        // Since it has layers greater than 64, the instance should take up two memory blocks
356        let layers = RenderLayers::from_layers(&[1, 77]);
357        assert!(layers.0.len() == 2);
358        // When excluding that layer, it should drop the extra memory block
359        let layers = layers.without(77);
360        assert!(layers.0.len() == 1);
361    }
362
363    #[test]
364    fn render_layer_iter_no_overflow() {
365        let layers = RenderLayers::from_layers(&[63]);
366        layers.iter().count();
367    }
368}