1use crate::shape::ShapeDesc;
2
3#[derive(Clone, Copy, Debug, PartialEq)]
4pub struct BodyHandle {
5 pub id: u32,
6 pub generation: u32,
7}
8
9#[derive(Clone, Copy, Debug, PartialEq)]
10pub struct BodyState {
11 pub position: [f32; 3],
12 pub orientation: [f32; 4],
13 pub velocity: [f32; 3],
14 pub angular_velocity: [f32; 3],
15 pub inverse_mass: f32,
16 pub step: u64,
17}
18
19pub const DEFAULT_COLLISION_GROUP: u32 = 0x0000_0001;
20pub const DEFAULT_COLLISION_MASK: u32 = 0xFFFF_FFFF;
21
22#[derive(Clone, Copy)]
23pub struct BodyDesc {
24 pub shape: ShapeDesc,
25 pub position: [f32; 3],
26 pub orientation: [f32; 4],
27 pub velocity: [f32; 3],
28 pub angular_velocity: [f32; 3],
29 pub mass: f32,
30 pub restitution: f32,
31 pub friction: f32,
32 pub collision_group: u32,
33 pub collision_mask: u32,
34 pub kinematic: bool,
35}
36
37impl BodyDesc {
38 pub fn sphere(radius: f32) -> Self {
39 assert!(radius > 0.0, "collider radius must be strictly positive");
40 Self::new(ShapeDesc::sphere(radius))
41 }
42
43 pub fn cuboid(half_extents: [f32; 3]) -> Self {
44 assert!(
45 half_extents.iter().all(|extent| *extent > 0.0),
46 "box half extents must be strictly positive"
47 );
48 Self::new(ShapeDesc::cuboid(half_extents))
49 }
50
51 pub fn capsule(radius: f32, half_height: f32) -> Self {
52 assert!(radius > 0.0, "capsule radius must be strictly positive");
53 assert!(
54 half_height >= 0.0,
55 "capsule half height must be non-negative"
56 );
57 Self::new(ShapeDesc::capsule(radius, half_height))
58 }
59
60 pub fn new(shape: ShapeDesc) -> Self {
61 Self {
62 shape,
63 position: [0.0; 3],
64 orientation: [0.0, 0.0, 0.0, 1.0],
65 velocity: [0.0; 3],
66 angular_velocity: [0.0; 3],
67 mass: 1.0,
68 restitution: 0.0,
69 friction: 0.5,
70 collision_group: DEFAULT_COLLISION_GROUP,
71 collision_mask: DEFAULT_COLLISION_MASK,
72 kinematic: false,
73 }
74 }
75
76 pub fn static_sphere(radius: f32) -> Self {
77 Self {
78 mass: 0.0,
79 ..Self::sphere(radius)
80 }
81 }
82
83 pub fn position(mut self, position: [f32; 3]) -> Self {
84 self.position = position;
85 self
86 }
87
88 pub fn orientation(mut self, orientation: [f32; 4]) -> Self {
89 assert!(
90 (orientation[0] * orientation[0]
91 + orientation[1] * orientation[1]
92 + orientation[2] * orientation[2]
93 + orientation[3] * orientation[3]
94 - 1.0)
95 .abs()
96 < 1e-4,
97 "orientation must be a unit quaternion"
98 );
99 self.orientation = orientation;
100 self
101 }
102
103 pub fn velocity(mut self, velocity: [f32; 3]) -> Self {
104 self.velocity = velocity;
105 self
106 }
107
108 pub fn angular_velocity(mut self, angular_velocity: [f32; 3]) -> Self {
109 self.angular_velocity = angular_velocity;
110 self
111 }
112
113 pub fn mass(mut self, mass: f32) -> Self {
114 assert!(mass >= 0.0, "mass must be non-negative");
115 self.mass = mass;
116 self
117 }
118
119 pub fn restitution(mut self, restitution: f32) -> Self {
120 self.restitution = restitution;
121 self
122 }
123
124 pub fn friction(mut self, friction: f32) -> Self {
125 assert!(friction >= 0.0, "friction must be non-negative");
126 self.friction = friction;
127 self
128 }
129
130 pub fn collision_group(mut self, group: u32) -> Self {
131 self.collision_group = group;
132 self
133 }
134
135 pub fn collision_mask(mut self, mask: u32) -> Self {
136 self.collision_mask = mask;
137 self
138 }
139
140 pub fn kinematic(mut self, kinematic: bool) -> Self {
141 self.kinematic = kinematic;
142 self
143 }
144}