logo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use super::*;

/// Bounds component.
///
/// Use to set custom bounds or read bounds defined by a mesh.
///
/// If an entity has a render component and it doesn't exist it will be added and
/// set to match the mesh, but will be available a frame later.

pub struct Bounds {
    id: Entity,
}

impl Bounds {
    /// Get the local space bounding box.
    ///
    /// Convenience for calling [`Self::bounding_box_min`] and [`Self::bounding_box_max`].
    pub fn bounding_box(&self) -> macaw::BoundingBox {
        // TODO: optimize to one FFI call
        macaw::BoundingBox {
            min: self.bounding_box_min().get(),
            max: self.bounding_box_max().get(),
        }
    }

    /// Set the local space bounding box.
    ///
    /// Convenience for calling [`Self::bounding_box_min`] and [`Self::bounding_box_max`].
    pub fn set_bounding_box(&self, bbox: macaw::BoundingBox) {
        // TODO: optimize to one FFI call
        self.bounding_box_min().set(bbox.min);
        self.bounding_box_max().set(bbox.max);
    }
}

impl std::fmt::Debug for Bounds {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Bounds")
            .field("entity", &self.id.name())
            .field("bounding_box_min", &self.bounding_box_min().get())
            .field("bounding_box_max", &self.bounding_box_max().get())
            .field(
                "bounding_sphere_radius",
                &self.bounding_sphere_radius().get(),
            )
            .field("match_render_shape", &self.match_render_shape().get())
            .finish()
    }
}

impl Bounds {
    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the bounding box min of the entity.
        ///
        /// Used to set/get/animate the min.
        ///
        /// For physics this will be used when the body is setup, for spatial queries it will be used as is.
        Bounds,
        BoundingBoxMin,
        Vec3,
        bounding_box_min,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the bounding box max of the entity.
        ///
        /// Used to set/get/animate the max.
        ///
        /// For physics this will be used when the body is setup, for spatial queries it will be used as is.
        Bounds,
        BoundingBoxMax,
        Vec3,
        bounding_box_max,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the bounding sphere radius of the entity.
        ///
        /// Used to set/get/animate the radius.
        ///
        /// For physics this will be used when the body is setup, for spatial queries it will be used as is.
        Bounds,
        BoundingSphereRadius,
        f32,
        bounding_sphere_radius,
        ValueAccessorReadWriteAnimate
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the match render shape toggle of the entity.
        ///
        /// Used to set/get whether these bounds will match the render shape.
        ///
        /// Set this to false if you want to set a custom bounding shape, box or sphere when the entity has a render component with a shape set.
        Bounds,
        MatchRenderShape,
        bool,
        match_render_shape,
        ValueAccessorReadWrite
    );

    impl_world_accessor!(
        /// Returns a `ValueAccessor` for the bounding shape of the entity.
        ///
        /// Used to set/get the bounding shape.
        ///
        /// Use this to set a custom collider/physics/spatial query shape with MatchRenderShape set to false.
        Bounds,
        BoundingShape,
        Shape,
        shape,
        ValueAccessorDataReadWrite
    );

    /// Convenience method to set up both the sphere and the bounding box
    /// to contain a certain radius.
    ///
    pub fn create_sphere_bounds(&self, radius: f32) {
        self.set_bounding_box(macaw::BoundingBox::from_min_max(
            Vec3::splat(-radius),
            Vec3::splat(radius),
        ));
        self.bounding_sphere_radius().set(radius);
        self.match_render_shape().set(false);
    }
}

impl_world_component!(Bounds);