blobs/
lib.rs

1use std::{
2    fmt::Debug,
3    sync::mpsc::{Receiver, Sender},
4};
5
6pub mod perf_counters;
7use crate::perf_counters::*;
8
9pub use atomic_refcell::{AtomicRef, AtomicRefCell};
10pub use once_cell::sync::Lazy;
11pub use std::borrow::Cow;
12pub use std::collections::HashMap;
13pub use std::rc::Rc;
14
15use glam::*;
16
17use itertools::Itertools;
18use thunderdome::{Arena, Index};
19
20mod collider;
21mod debug;
22mod events;
23mod groups;
24mod joints;
25mod physics;
26mod query_filter;
27mod rigid_body;
28mod spatial;
29mod springs;
30mod tests;
31
32pub use crate::collider::*;
33pub use crate::debug::*;
34pub use crate::events::*;
35pub use crate::groups::*;
36pub use crate::joints::*;
37pub use crate::physics::*;
38pub use crate::query_filter::*;
39pub use crate::rigid_body::*;
40pub use crate::spatial::*;
41pub use crate::springs::*;
42
43#[derive(Copy, Clone, Debug)]
44pub struct Velocity(pub Vec2);
45
46#[derive(Clone, Debug)]
47pub struct Ball {
48    pub radius: f32,
49}
50
51impl Shape for Ball {
52    fn as_ball(&self) -> Option<&Ball> {
53        Some(self)
54    }
55
56    fn as_cuboid(&self) -> Option<&Cuboid> {
57        None
58    }
59
60    fn calculate_aabb(&self, transform: Affine2) -> AABB {
61        let min = transform.translation - vec2(self.radius, self.radius);
62        let max = transform.translation + vec2(self.radius, self.radius);
63
64        AABB::new(min, max)
65    }
66}
67
68impl Ball {
69    pub fn new(radius: f32) -> Self {
70        Self { radius }
71    }
72}
73
74pub trait Shape: 'static + Debug {
75    fn as_ball(&self) -> Option<&Ball>;
76    fn as_cuboid(&self) -> Option<&Cuboid>;
77    fn calculate_aabb(&self, transform: Affine2) -> AABB;
78}
79
80#[derive(Debug, Clone, Copy)]
81pub struct AABB {
82    pub min: Vec2,
83    pub max: Vec2,
84}
85
86impl AABB {
87    pub fn new(min: Vec2, max: Vec2) -> Self {
88        Self { min, max }
89    }
90
91    pub fn from_two_points(a: Vec2, b: Vec2) -> Self {
92        Self {
93            min: a.min(b),
94            max: a.max(b),
95        }
96    }
97
98    pub fn from_top_left(top_left: Vec2, size: Vec2) -> Self {
99        Self::from_center_size(
100            vec2(top_left.x + size.x / 2.0, top_left.y - size.y / 2.0),
101            size,
102        )
103    }
104
105    pub fn from_center_size(center: Vec2, size: Vec2) -> Self {
106        let half_size = size * 0.5;
107        Self {
108            min: center - half_size,
109            max: center + half_size,
110        }
111    }
112
113    pub fn center(&self) -> Vec2 {
114        (self.min + self.max) * 0.5
115    }
116
117    pub fn size(&self) -> Vec2 {
118        self.max - self.min
119    }
120
121    pub fn contains(&self, point: Vec2) -> bool {
122        self.min.x <= point.x
123            && self.min.y <= point.y
124            && self.max.x >= point.x
125            && self.max.y >= point.y
126    }
127
128    pub fn intersects(&self, other: &AABB) -> bool {
129        self.min.x <= other.max.x
130            && self.max.x >= other.min.x
131            && self.min.y <= other.max.y
132            && self.max.y >= other.min.y
133    }
134
135    pub fn expand_to_include_point(&mut self, point: Vec2) {
136        self.min = self.min.min(point);
137        self.max = self.max.max(point);
138    }
139
140    pub fn expand_to_include_aabb(&mut self, other: &AABB) {
141        self.min = self.min.min(other.min);
142        self.max = self.max.max(other.max);
143    }
144}
145
146#[derive(Copy, Clone, Debug)]
147pub struct CollisionEvent {
148    pub col_handle_a: ColliderHandle,
149    pub col_handle_b: ColliderHandle,
150
151    pub impact_vel_a: Vec2,
152    pub impact_vel_b: Vec2,
153}
154
155pub struct Rotation {}
156
157impl Rotation {
158    pub fn angle(&self) -> f32 {
159        todo!()
160    }
161}
162
163pub struct Cuboid {
164    pub half_extents: Vec2,
165}
166
167pub struct QueryPipeline {
168    #[allow(dead_code)]
169    time_data: Rc<TimeData>,
170}
171
172impl QueryPipeline {
173    pub fn new(time_data: Rc<TimeData>) -> Self {
174        Self { time_data }
175    }
176
177    pub fn intersection_with_shape(
178        &self,
179        _rbd_set: &RigidBodySet,
180        _col_set: &ColliderSet,
181        _position: &Vec2,
182        _shape: &dyn Shape,
183        _filter: QueryFilter,
184    ) -> Option<ColliderHandle> {
185        None
186    }
187}
188
189// Circle constraint
190pub struct Constraint {
191    pub position: Vec2,
192    pub radius: f32,
193}
194
195#[cfg(feature = "tracy")]
196#[macro_export]
197macro_rules! tracy_span {
198    ($name: expr) => {
199        Some(tracy_client::span!($name, 0))
200    };
201}
202
203#[cfg(not(feature = "tracy"))]
204#[macro_export]
205macro_rules! tracy_span {
206    ($name: expr) => {
207        None::<()>
208    };
209}
210
211pub trait ZipTuple<A, B> {
212    fn zip(self) -> Option<(A, B)>;
213    fn zip_unwrap(self) -> (A, B);
214}
215
216impl<A, B> ZipTuple<A, B> for (Option<A>, Option<B>) {
217    fn zip(self) -> Option<(A, B)> {
218        match self {
219            (Some(a), Some(b)) => Some((a, b)),
220            _ => None,
221        }
222    }
223
224    fn zip_unwrap(self) -> (A, B) {
225        self.zip().unwrap()
226    }
227}
228
229pub trait AffineExtensions {
230    fn angle(&self) -> f32;
231    fn angle_dir(&self) -> Vec2;
232}
233
234impl AffineExtensions for Affine2 {
235    fn angle(&self) -> f32 {
236        // NOTE: This breaks if the transform has a scale or shear component
237        let up = vec2(0.0, 1.0);
238        // up.angle_between(self.transform_vector2(up))
239        self.transform_vector2(up).angle_between(up)
240    }
241
242    fn angle_dir(&self) -> Vec2 {
243        let angle = self.angle();
244        Vec2::from_angle(angle)
245    }
246}