bevy_camera/visibility/
render_layers.rs

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