Skip to main content

bevy_aabb_instancing/
cuboids.rs

1use bevy::{
2    prelude::*,
3    render::{primitives::Aabb, render_resource::ShaderType},
4};
5
6use crate::CuboidMaterialId;
7
8/// Value that determines the color of a [`Cuboid`] based on the associated
9/// [`CuboidMaterial`](crate::CuboidMaterial).
10pub type Color = u32;
11
12/// Metadata encoded in 32 bits:
13///
14/// - `0x000000FF`
15///     - bit 0 = 0 for visible or 1 for invisible
16///     - bit 1 = 0 for non-emissive or 1 for emissive
17///     - bits 2-7 = unused
18/// - `0x0000FF00` = unused
19/// - `0xFFFF0000` = depth bias (u16)
20///   - Multiplies the depth of each cuboid vertex by `1 - bias * eps` where
21///     `eps = 8e-8`. This can be used with random biases to avoid Z-fighting.
22pub type MetaBits = u32;
23
24/// An axis-aligned box, extending from `minimum` to `maximum`.
25#[derive(Clone, Copy, Debug, ShaderType)]
26#[repr(C)]
27pub struct Cuboid {
28    pub minimum: Vec3,
29    pub meta_bits: MetaBits,
30    pub maximum: Vec3,
31    pub color: Color,
32}
33
34impl Cuboid {
35    pub fn new(minimum: Vec3, maximum: Vec3, color: u32) -> Self {
36        assert_eq!(std::mem::size_of::<Cuboid>(), 32);
37        Self {
38            minimum,
39            meta_bits: 0,
40            maximum,
41            color,
42        }
43    }
44
45    #[inline]
46    pub fn make_visible(&mut self) -> &mut Self {
47        self.meta_bits &= !1;
48        self
49    }
50
51    #[inline]
52    pub fn make_invisible(&mut self) -> &mut Self {
53        self.meta_bits |= 1;
54        self
55    }
56
57    #[inline]
58    pub fn make_emissive(&mut self) -> &mut Self {
59        self.meta_bits |= 0b10;
60        self
61    }
62
63    #[inline]
64    pub fn make_non_emissive(&mut self) -> &mut Self {
65        self.meta_bits &= !0b10;
66        self
67    }
68
69    #[inline]
70    pub fn set_depth_bias(&mut self, bias: u16) -> &mut Self {
71        self.meta_bits &= 0x0000FFFF; // clear
72        self.meta_bits |= (bias as u32) << 16; // set
73        self
74    }
75}
76
77/// A set of cuboids to be extracted for rendering.
78#[derive(Clone, Component, Debug, Default)]
79pub struct Cuboids {
80    /// Instances to be rendered.
81    pub instances: Vec<Cuboid>,
82}
83
84impl Cuboids {
85    pub fn new(instances: Vec<Cuboid>) -> Self {
86        Self { instances }
87    }
88
89    /// Automatically creates an [`Aabb`] that bounds all `instances`.
90    pub fn aabb(&self) -> Aabb {
91        let mut min = Vec3::splat(f32::MAX);
92        let mut max = Vec3::splat(f32::MIN);
93        for i in self.instances.iter() {
94            min = min.min(i.minimum);
95            max = max.max(i.maximum);
96        }
97        Aabb::from_min_max(min, max)
98    }
99}
100
101#[derive(Clone, ShaderType)]
102pub(crate) struct CuboidsTransform {
103    pub matrix: Mat4,
104    pub inv_matrix: Mat4,
105}
106
107impl CuboidsTransform {
108    pub fn new(matrix: Mat4, inv_matrix: Mat4) -> Self {
109        Self { matrix, inv_matrix }
110    }
111
112    pub fn from_matrix(m: Mat4) -> Self {
113        Self::new(m, m.inverse())
114    }
115
116    pub fn position(&self) -> Vec3 {
117        self.matrix.col(3).truncate()
118    }
119}
120
121#[derive(Bundle)]
122pub struct CuboidsBundle {
123    pub material_id: CuboidMaterialId,
124    pub cuboids: Cuboids,
125    pub spatial: SpatialBundle,
126}