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
189pub 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 let up = vec2(0.0, 1.0);
238 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}