1pub type BodyId = u32;
2pub type ConstraintId = u32;
3
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum BodyType {
6 Static,
7 Dynamic,
8 Kinematic,
9}
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum Shape {
13 Circle { radius: f32 },
14 AABB { half_w: f32, half_h: f32 },
15 Polygon { vertices: Vec<(f32, f32)> },
16}
17
18#[derive(Debug, Clone, Copy, PartialEq)]
19pub struct Material {
20 pub restitution: f32,
21 pub friction: f32,
22}
23
24impl Default for Material {
25 fn default() -> Self {
26 Self {
27 restitution: 0.3,
28 friction: 0.5,
29 }
30 }
31}
32
33#[derive(Debug, Clone)]
34pub struct RigidBody {
35 pub id: BodyId,
36 pub body_type: BodyType,
37 pub shape: Shape,
38 pub material: Material,
39 pub x: f32,
40 pub y: f32,
41 pub angle: f32,
42 pub vx: f32,
43 pub vy: f32,
44 pub angular_velocity: f32,
45 pub fx: f32,
46 pub fy: f32,
47 pub torque: f32,
48 pub mass: f32,
49 pub inv_mass: f32,
50 pub inertia: f32,
51 pub inv_inertia: f32,
52 pub layer: u16,
53 pub mask: u16,
54 pub sleeping: bool,
55 pub sleep_timer: f32,
56}
57
58#[derive(Debug, Clone)]
59pub struct Contact {
60 pub body_a: BodyId,
61 pub body_b: BodyId,
62 pub normal: (f32, f32),
63 pub penetration: f32,
64 pub contact_point: (f32, f32),
65 pub accumulated_jn: f32,
67 pub accumulated_jt: f32,
69 pub velocity_bias: f32,
71 pub tangent: (f32, f32),
73}
74
75#[derive(Debug, Clone)]
76pub enum Constraint {
77 Distance {
78 id: ConstraintId,
79 body_a: BodyId,
80 body_b: BodyId,
81 distance: f32,
82 anchor_a: (f32, f32),
83 anchor_b: (f32, f32),
84 },
85 Revolute {
86 id: ConstraintId,
87 body_a: BodyId,
88 body_b: BodyId,
89 pivot: (f32, f32),
90 },
91}
92
93impl Constraint {
94 pub fn id(&self) -> ConstraintId {
95 match self {
96 Constraint::Distance { id, .. } => *id,
97 Constraint::Revolute { id, .. } => *id,
98 }
99 }
100}
101
102pub fn compute_mass_and_inertia(shape: &Shape, mass: f32, body_type: BodyType) -> (f32, f32, f32) {
105 if body_type == BodyType::Static || mass <= 0.0 {
106 return (0.0, 0.0, 0.0);
107 }
108 let inv_mass = 1.0 / mass;
109 let inertia = match shape {
110 Shape::Circle { radius } => 0.5 * mass * radius * radius,
111 Shape::AABB { .. } => {
112 0.0
117 }
118 Shape::Polygon { vertices } => {
119 compute_polygon_inertia(vertices, mass)
121 }
122 };
123 let inv_inertia = if inertia > 0.0 { 1.0 / inertia } else { 0.0 };
124 (inv_mass, inertia, inv_inertia)
125}
126
127fn compute_polygon_inertia(vertices: &[(f32, f32)], mass: f32) -> f32 {
128 let n = vertices.len();
129 if n < 3 {
130 return 0.0;
131 }
132 let mut numerator = 0.0f32;
133 let mut denominator = 0.0f32;
134 for i in 0..n {
135 let (x0, y0) = vertices[i];
136 let (x1, y1) = vertices[(i + 1) % n];
137 let cross = (x0 * y1 - x1 * y0).abs();
138 numerator += cross * (x0 * x0 + x0 * x1 + x1 * x1 + y0 * y0 + y0 * y1 + y1 * y1);
139 denominator += cross;
140 }
141 if denominator == 0.0 {
142 return 0.0;
143 }
144 mass * numerator / (6.0 * denominator)
145}
146
147pub fn get_shape_aabb(body: &RigidBody) -> (f32, f32, f32, f32) {
149 match &body.shape {
150 Shape::Circle { radius } => (
151 body.x - radius,
152 body.y - radius,
153 body.x + radius,
154 body.y + radius,
155 ),
156 Shape::AABB { half_w, half_h } => {
157 if body.angle.abs() < 1e-6 {
158 (
159 body.x - half_w,
160 body.y - half_h,
161 body.x + half_w,
162 body.y + half_h,
163 )
164 } else {
165 let cos = body.angle.cos();
167 let sin = body.angle.sin();
168 let hw = (half_w * cos.abs()) + (half_h * sin.abs());
169 let hh = (half_w * sin.abs()) + (half_h * cos.abs());
170 (body.x - hw, body.y - hh, body.x + hw, body.y + hh)
171 }
172 }
173 Shape::Polygon { vertices } => {
174 if vertices.is_empty() {
175 return (body.x, body.y, body.x, body.y);
176 }
177 let cos = body.angle.cos();
178 let sin = body.angle.sin();
179 let mut min_x = f32::MAX;
180 let mut min_y = f32::MAX;
181 let mut max_x = f32::MIN;
182 let mut max_y = f32::MIN;
183 for &(vx, vy) in vertices {
184 let rx = vx * cos - vy * sin + body.x;
185 let ry = vx * sin + vy * cos + body.y;
186 min_x = min_x.min(rx);
187 min_y = min_y.min(ry);
188 max_x = max_x.max(rx);
189 max_y = max_y.max(ry);
190 }
191 (min_x, min_y, max_x, max_y)
192 }
193 }
194}