Skip to main content

avian3d/collider_tree/
proxy_key.rs

1use core::hint::unreachable_unchecked;
2
3use bevy::{
4    ecs::{
5        component::Component,
6        entity::{ComponentCloneCtx, SourceComponent},
7    },
8    reflect::Reflect,
9};
10
11use crate::prelude::RigidBody;
12
13/// A key for a proxy in a [`ColliderTree`], encoding both
14/// the [`ProxyId`] and the [`ColliderTreeType`].
15///
16/// The tree type is stored in the lower 2 bits of the key,
17/// leaving 30 bits for the [`ProxyId`].
18///
19/// [`ColliderTree`]: crate::collider_tree::ColliderTree
20#[derive(Component, Clone, Copy, Debug, PartialEq, Eq, Hash, Reflect)]
21#[component(clone_behavior = Custom(clone_placeholder_proxy_key))]
22pub struct ColliderTreeProxyKey(u32);
23
24// Avoid aliasing keys when cloning colliders
25fn clone_placeholder_proxy_key(_source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
26    ctx.write_target_component(ColliderTreeProxyKey::PLACEHOLDER);
27}
28
29impl ColliderTreeProxyKey {
30    /// A placeholder proxy key used before the proxy is actually created.
31    pub const PLACEHOLDER: Self = ColliderTreeProxyKey(u32::MAX);
32
33    /// Creates a new [`ColliderTreeProxyKey`] from the given [`ProxyId`] and tree type.
34    #[inline]
35    pub const fn new(id: ProxyId, tree_type: ColliderTreeType) -> Self {
36        // Encode the tree type in the lower 2 bits.
37        ColliderTreeProxyKey((id.id() << 2) | (tree_type as u32))
38    }
39
40    /// Returns the [`ProxyId`] of the proxy.
41    #[inline]
42    pub const fn id(&self) -> ProxyId {
43        ProxyId::new(self.0 >> 2)
44    }
45
46    /// Returns the [`ColliderTreeType`] of the proxy.
47    #[inline]
48    pub const fn tree_type(&self) -> ColliderTreeType {
49        match self.0 & 0b11 {
50            0 => ColliderTreeType::Dynamic,
51            1 => ColliderTreeType::Kinematic,
52            2 => ColliderTreeType::Static,
53            3 => ColliderTreeType::Standalone,
54            // Safety: Bitwise AND with 0b11 can only yield 0, 1, 2, or 3.
55            _ => unsafe { unreachable_unchecked() },
56        }
57    }
58
59    /// Returns the rigid body type associated with the proxy.
60    ///
61    /// If the proxy is a standalone collider with no body, returns `None`.
62    #[inline]
63    pub const fn body(&self) -> Option<RigidBody> {
64        match self.0 & 0b11 {
65            0 => Some(RigidBody::Dynamic),
66            1 => Some(RigidBody::Kinematic),
67            2 => Some(RigidBody::Static),
68            3 => None,
69            // Safety: Bitwise AND with 0b11 can only yield 0, 1, 2, or 3.
70            _ => unsafe { unreachable_unchecked() },
71        }
72    }
73
74    /// Returns `true` if the proxy belongs to a dynamic body.
75    #[inline]
76    pub const fn is_dynamic(&self) -> bool {
77        if let Some(body) = self.body() {
78            body as u32 == RigidBody::Dynamic as u32
79        } else {
80            false
81        }
82    }
83
84    /// Returns `true` if the proxy belongs to a kinematic body.
85    #[inline]
86    pub const fn is_kinematic(&self) -> bool {
87        if let Some(body) = self.body() {
88            body as u32 == RigidBody::Kinematic as u32
89        } else {
90            false
91        }
92    }
93
94    /// Returns `true` if the proxy belongs to a static body.
95    #[inline]
96    pub const fn is_static(&self) -> bool {
97        if let Some(body) = self.body() {
98            body as u32 == RigidBody::Static as u32
99        } else {
100            false
101        }
102    }
103
104    /// Returns `true` if the proxy is a standalone collider with no body.
105    #[inline]
106    pub const fn is_standalone(&self) -> bool {
107        self.body().is_none()
108    }
109}
110
111/// A stable identifier for a proxy in a [`ColliderTree`].
112///
113/// [`ColliderTree`]: crate::collider_tree::ColliderTree
114#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Reflect)]
115pub struct ProxyId(u32);
116
117impl ProxyId {
118    /// A placeholder proxy ID used before the proxy is actually created.
119    pub const PLACEHOLDER: Self = ProxyId(u32::MAX >> 2);
120
121    /// Creates a new [`ProxyId`] from the given `u32` identifier.
122    ///
123    /// Only the lower 30 bits should be used for the ID.
124    ///
125    /// # Panics
126    ///
127    /// Panics if either of the upper 2 bits are set and `debug_assertions` are enabled.
128    #[inline]
129    pub const fn new(id: u32) -> Self {
130        debug_assert!(id < (1 << 30), "ProxyId can only use lower 30 bits");
131        ProxyId(id)
132    }
133
134    /// Returns the proxy ID as a `u32`.
135    #[inline]
136    pub const fn id(&self) -> u32 {
137        self.0
138    }
139
140    /// Returns the proxy ID as a `usize`.
141    #[inline]
142    pub const fn index(&self) -> usize {
143        self.0 as usize
144    }
145}
146
147impl From<u32> for ProxyId {
148    #[inline]
149    fn from(id: u32) -> Self {
150        ProxyId::new(id)
151    }
152}
153
154impl From<ProxyId> for u32 {
155    #[inline]
156    fn from(proxy_id: ProxyId) -> Self {
157        proxy_id.id()
158    }
159}
160
161impl PartialOrd for ProxyId {
162    #[inline]
163    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
164        Some(self.cmp(other))
165    }
166}
167
168impl Ord for ProxyId {
169    #[inline]
170    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
171        self.0.cmp(&other.0)
172    }
173}
174
175/// The type of a collider tree, corresponding to the rigid body type.
176#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Reflect)]
177pub enum ColliderTreeType {
178    /// A tree for dynamic bodies.
179    Dynamic = 0,
180    /// A tree for kinematic bodies.
181    Kinematic = 1,
182    /// A tree for static bodies.
183    Static = 2,
184    /// A tree for standalone colliders with no associated rigid body.
185    Standalone = 3,
186}
187
188impl ColliderTreeType {
189    /// An array of all possible [`ColliderTreeType`]s.
190    pub const ALL: [ColliderTreeType; 4] = [
191        ColliderTreeType::Dynamic,
192        ColliderTreeType::Kinematic,
193        ColliderTreeType::Static,
194        ColliderTreeType::Standalone,
195    ];
196
197    /// Creates a new [`ColliderTreeType`] from the given optional rigid body type.
198    ///
199    /// `None` corresponds to standalone colliders with no body.
200    #[inline]
201    pub const fn from_body(body: Option<RigidBody>) -> Self {
202        match body {
203            Some(RigidBody::Dynamic) => ColliderTreeType::Dynamic,
204            Some(RigidBody::Kinematic) => ColliderTreeType::Kinematic,
205            Some(RigidBody::Static) => ColliderTreeType::Static,
206            None => ColliderTreeType::Standalone,
207        }
208    }
209
210    /// Returns `true` if the tree type is for dynamic bodies.
211    #[inline]
212    pub const fn is_dynamic(&self) -> bool {
213        matches!(self, ColliderTreeType::Dynamic)
214    }
215
216    /// Returns `true` if the tree type is for kinematic bodies.
217    #[inline]
218    pub const fn is_kinematic(&self) -> bool {
219        matches!(self, ColliderTreeType::Kinematic)
220    }
221
222    /// Returns `true` if the tree type is for static bodies.
223    #[inline]
224    pub const fn is_static(&self) -> bool {
225        matches!(self, ColliderTreeType::Static)
226    }
227
228    /// Returns `true` if the tree type is for standalone colliders with no body.
229    #[inline]
230    pub const fn is_standalone(&self) -> bool {
231        matches!(self, ColliderTreeType::Standalone)
232    }
233}
234
235impl From<Option<RigidBody>> for ColliderTreeType {
236    #[inline]
237    fn from(body: Option<RigidBody>) -> Self {
238        match body {
239            Some(RigidBody::Dynamic) => ColliderTreeType::Dynamic,
240            Some(RigidBody::Kinematic) => ColliderTreeType::Kinematic,
241            Some(RigidBody::Static) => ColliderTreeType::Static,
242            None => ColliderTreeType::Standalone,
243        }
244    }
245}
246
247impl From<ColliderTreeType> for Option<RigidBody> {
248    #[inline]
249    fn from(tree_type: ColliderTreeType) -> Self {
250        match tree_type {
251            ColliderTreeType::Dynamic => Some(RigidBody::Dynamic),
252            ColliderTreeType::Kinematic => Some(RigidBody::Kinematic),
253            ColliderTreeType::Static => Some(RigidBody::Static),
254            ColliderTreeType::Standalone => None,
255        }
256    }
257}
258
259impl From<RigidBody> for ColliderTreeType {
260    #[inline]
261    fn from(body: RigidBody) -> Self {
262        match body {
263            RigidBody::Dynamic => ColliderTreeType::Dynamic,
264            RigidBody::Kinematic => ColliderTreeType::Kinematic,
265            RigidBody::Static => ColliderTreeType::Static,
266        }
267    }
268}