Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_camera/src/visibility/render_layers.rs
6599 views
1
use bevy_ecs::prelude::{Component, ReflectComponent};
2
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
3
use smallvec::SmallVec;
4
5
pub const DEFAULT_LAYERS: &RenderLayers = &RenderLayers::layer(0);
6
7
/// An identifier for a rendering layer.
8
pub 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)]
20
pub struct RenderLayers(SmallVec<[u64; INLINE_BLOCKS]>);
21
22
/// The number of memory blocks stored inline
23
const INLINE_BLOCKS: usize = 1;
24
25
impl Default for &RenderLayers {
26
fn default() -> Self {
27
DEFAULT_LAYERS
28
}
29
}
30
31
impl 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
39
impl 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
45
impl 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
54
impl 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
225
impl core::ops::BitAnd for RenderLayers {
226
type Output = Self;
227
fn bitand(self, rhs: Self) -> Self::Output {
228
self.intersection(&rhs)
229
}
230
}
231
232
impl core::ops::BitOr for RenderLayers {
233
type Output = Self;
234
fn bitor(self, rhs: Self) -> Self::Output {
235
self.union(&rhs)
236
}
237
}
238
239
impl 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)]
247
mod 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
}
368
369