1use std::fmt;
2use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
3
4#[repr(C)]
6#[derive(Clone, Copy, Debug, Default, PartialEq)]
7pub struct Vec3 {
8 pub x: f32,
9 pub y: f32,
10 pub z: f32,
11}
12
13impl Vec3 {
14 pub const ZERO: Self = Self {
15 x: 0.0,
16 y: 0.0,
17 z: 0.0,
18 };
19
20 pub const fn new(x: f32, y: f32, z: f32) -> Self {
21 Self { x, y, z }
22 }
23
24 pub fn dot(self, other: Self) -> f32 {
25 self.x * other.x + self.y * other.y + self.z * other.z
26 }
27
28 pub fn cross(self, other: Self) -> Self {
29 Self::new(
30 self.y * other.z - self.z * other.y,
31 self.z * other.x - self.x * other.z,
32 self.x * other.y - self.y * other.x,
33 )
34 }
35
36 pub fn magnitude_squared(self) -> f32 {
37 self.dot(self)
38 }
39
40 pub fn magnitude(self) -> f32 {
41 self.magnitude_squared().sqrt()
42 }
43
44 pub fn normalize(self) -> Self {
45 let mag = self.magnitude();
46 if mag > 0.0 {
47 self / mag
48 } else {
49 Self::default()
50 }
51 }
52}
53
54impl Add for Vec3 {
55 type Output = Self;
56 fn add(self, rhs: Self) -> Self {
57 Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
58 }
59}
60
61impl AddAssign for Vec3 {
62 fn add_assign(&mut self, rhs: Self) {
63 self.x += rhs.x;
64 self.y += rhs.y;
65 self.z += rhs.z;
66 }
67}
68
69impl Sub for Vec3 {
70 type Output = Self;
71 fn sub(self, rhs: Self) -> Self {
72 Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
73 }
74}
75
76impl SubAssign for Vec3 {
77 fn sub_assign(&mut self, rhs: Self) {
78 self.x -= rhs.x;
79 self.y -= rhs.y;
80 self.z -= rhs.z;
81 }
82}
83
84impl Mul<f32> for Vec3 {
85 type Output = Self;
86 fn mul(self, rhs: f32) -> Self {
87 Self::new(self.x * rhs, self.y * rhs, self.z * rhs)
88 }
89}
90
91impl MulAssign<f32> for Vec3 {
92 fn mul_assign(&mut self, rhs: f32) {
93 self.x *= rhs;
94 self.y *= rhs;
95 self.z *= rhs;
96 }
97}
98
99impl Div<f32> for Vec3 {
100 type Output = Self;
101 fn div(self, rhs: f32) -> Self {
102 Self::new(self.x / rhs, self.y / rhs, self.z / rhs)
103 }
104}
105
106impl DivAssign<f32> for Vec3 {
107 fn div_assign(&mut self, rhs: f32) {
108 self.x /= rhs;
109 self.y /= rhs;
110 self.z /= rhs;
111 }
112}
113
114impl Neg for Vec3 {
115 type Output = Self;
116 fn neg(self) -> Self {
117 Self::new(-self.x, -self.y, -self.z)
118 }
119}
120
121#[derive(Clone, Copy, Debug, Default)]
124pub struct NodeDesc {
125 pub centroid: Vec3,
126 pub mass: f32,
127 pub volume: f32,
128}
129
130#[derive(Clone, Copy, Debug, Default)]
132pub struct BondDesc {
133 pub centroid: Vec3,
134 pub normal: Vec3,
135 pub area: f32,
136 pub node0: u32,
137 pub node1: u32,
138}
139
140#[derive(Clone, Copy, Debug)]
142pub struct SolverSettings {
143 pub max_solver_iterations_per_frame: u32,
144 pub graph_reduction_level: u32,
145 pub compression_elastic_limit: f32,
146 pub compression_fatal_limit: f32,
147 pub tension_elastic_limit: f32,
148 pub tension_fatal_limit: f32,
149 pub shear_elastic_limit: f32,
150 pub shear_fatal_limit: f32,
151}
152
153impl Default for SolverSettings {
154 fn default() -> Self {
155 Self {
156 max_solver_iterations_per_frame: 32,
157 graph_reduction_level: 0,
158 compression_elastic_limit: 1.0,
159 compression_fatal_limit: 2.0,
160 tension_elastic_limit: -1.0,
161 tension_fatal_limit: -1.0,
162 shear_elastic_limit: -1.0,
163 shear_fatal_limit: -1.0,
164 }
165 }
166}
167
168#[derive(Clone, Copy, Debug, Default)]
170pub struct BondStressResult {
171 pub compression: f32,
172 pub tension: f32,
173 pub shear: f32,
174}
175
176#[derive(Clone, Copy, Debug)]
178pub struct StressSeverity {
179 pub compression: f32,
180 pub tension: f32,
181 pub shear: f32,
182}
183
184impl StressSeverity {
185 pub fn max_component(&self) -> f32 {
186 self.compression.max(self.tension).max(self.shear)
187 }
188}
189
190#[derive(Clone, Copy, Debug, PartialEq, Eq)]
192pub enum StressFailure {
193 Compression,
194 Tension,
195 Shear,
196}
197
198impl fmt::Display for StressFailure {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 match self {
201 StressFailure::Compression => write!(f, "compression"),
202 StressFailure::Tension => write!(f, "tension"),
203 StressFailure::Shear => write!(f, "shear"),
204 }
205 }
206}
207
208#[derive(Clone, Copy, Debug)]
210pub struct StressLimits {
211 pub compression_elastic_limit: f32,
212 pub compression_fatal_limit: f32,
213 pub tension_elastic_limit: f32,
214 pub tension_fatal_limit: f32,
215 pub shear_elastic_limit: f32,
216 pub shear_fatal_limit: f32,
217}
218
219impl Default for StressLimits {
220 fn default() -> Self {
221 Self {
222 compression_elastic_limit: 1.0,
223 compression_fatal_limit: 2.0,
224 tension_elastic_limit: -1.0,
225 tension_fatal_limit: -1.0,
226 shear_elastic_limit: -1.0,
227 shear_fatal_limit: -1.0,
228 }
229 }
230}
231
232impl StressLimits {
233 fn resolve(limit: f32, fallback: f32) -> f32 {
234 if limit > 0.0 {
235 limit
236 } else if fallback > 0.0 {
237 fallback
238 } else {
239 1.0
240 }
241 }
242
243 pub fn compression_elastic(&self) -> f32 {
244 Self::resolve(self.compression_elastic_limit, 1.0)
245 }
246
247 pub fn compression_fatal(&self) -> f32 {
248 Self::resolve(self.compression_fatal_limit, self.compression_elastic())
249 }
250
251 pub fn tension_elastic(&self) -> f32 {
252 Self::resolve(self.tension_elastic_limit, self.compression_elastic())
253 }
254
255 pub fn tension_fatal(&self) -> f32 {
256 Self::resolve(self.tension_fatal_limit, self.compression_fatal())
257 }
258
259 pub fn shear_elastic(&self) -> f32 {
260 Self::resolve(self.shear_elastic_limit, self.compression_elastic())
261 }
262
263 pub fn shear_fatal(&self) -> f32 {
264 Self::resolve(self.shear_fatal_limit, self.compression_fatal())
265 }
266
267 fn map_stress_value(stress: f32, elastic: f32, fatal: f32) -> f32 {
268 if stress <= 0.0 {
269 return 0.0;
270 }
271 let elastic = if elastic > 0.0 { elastic } else { fatal };
272 let fatal = if fatal > 0.0 { fatal } else { elastic.max(1.0) };
273 if elastic > 0.0 && stress < elastic {
274 (stress / elastic * 0.5).clamp(0.0, 0.5)
275 } else if fatal > elastic && elastic > 0.0 {
276 (0.5 + 0.5 * (stress - elastic) / (fatal - elastic)).clamp(0.5, 1.0)
277 } else {
278 (stress / fatal).clamp(0.0, 1.0)
279 }
280 }
281
282 pub fn severity(&self, stress: &BondStressResult) -> StressSeverity {
284 StressSeverity {
285 compression: Self::map_stress_value(
286 stress.compression,
287 self.compression_elastic(),
288 self.compression_fatal(),
289 ),
290 tension: Self::map_stress_value(
291 stress.tension,
292 self.tension_elastic(),
293 self.tension_fatal(),
294 ),
295 shear: Self::map_stress_value(stress.shear, self.shear_elastic(), self.shear_fatal()),
296 }
297 }
298
299 pub fn failure_mode(&self, stress: &BondStressResult) -> Option<StressFailure> {
301 if stress.compression > self.compression_fatal() {
302 Some(StressFailure::Compression)
303 } else if stress.tension > self.tension_fatal() {
304 Some(StressFailure::Tension)
305 } else if stress.shear > self.shear_fatal() {
306 Some(StressFailure::Shear)
307 } else {
308 None
309 }
310 }
311}
312
313#[derive(Clone, Copy, Debug, PartialEq, Eq)]
315#[repr(u32)]
316pub enum ForceMode {
317 Force = 0,
318 Acceleration = 1,
319}
320
321#[derive(Clone, Copy, Debug, Default)]
323pub struct BondFracture {
324 pub userdata: u32,
325 pub node_index0: u32,
326 pub node_index1: u32,
327 pub health: f32,
328}
329
330#[derive(Clone, Debug, Default)]
332pub struct FractureCommand {
333 pub actor_index: u32,
334 pub bond_fractures: Vec<BondFracture>,
335}
336
337#[derive(Clone, Debug)]
339pub struct SplitChild {
340 pub actor_index: u32,
341 pub nodes: Vec<u32>,
342}
343
344#[derive(Clone, Debug)]
346pub struct SplitEvent {
347 pub parent_actor_index: u32,
348 pub children: Vec<SplitChild>,
349}
350
351#[derive(Clone, Debug)]
353pub struct Actor {
354 pub actor_index: u32,
355 pub nodes: Vec<u32>,
356}
357
358#[derive(Clone, Copy, Debug, Default)]
360pub struct ScenarioNode {
361 pub centroid: Vec3,
362 pub mass: f32,
363 pub volume: f32,
364}
365
366#[derive(Clone, Copy, Debug, Default)]
368pub struct ScenarioBond {
369 pub node0: u32,
370 pub node1: u32,
371 pub centroid: Vec3,
372 pub normal: Vec3,
373 pub area: f32,
374}
375
376#[derive(Clone, Debug)]
378pub enum ScenarioCollider {
379 Cuboid { half_extents: Vec3 },
380 ConvexHull { points: Vec<Vec3> },
381}
382
383#[derive(Clone, Debug, Default)]
385pub struct ScenarioDesc {
386 pub nodes: Vec<ScenarioNode>,
387 pub bonds: Vec<ScenarioBond>,
388 pub node_sizes: Vec<Vec3>,
391 pub collider_shapes: Vec<Option<ScenarioCollider>>,
394}
395
396impl ScenarioDesc {
397 pub fn to_solver_descs(&self) -> (Vec<NodeDesc>, Vec<BondDesc>) {
399 let nodes = self
400 .nodes
401 .iter()
402 .map(|n| NodeDesc {
403 centroid: n.centroid,
404 mass: n.mass,
405 volume: n.volume,
406 })
407 .collect();
408 let bonds = self
409 .bonds
410 .iter()
411 .map(|b| BondDesc {
412 centroid: b.centroid,
413 normal: b.normal,
414 area: b.area,
415 node0: b.node0,
416 node1: b.node1,
417 })
418 .collect();
419 (nodes, bonds)
420 }
421}