1use crate::ffi;
4use crate::types::*;
5
6pub struct ExtStressSolver {
11 handle: *mut ffi::ExtStressSolverHandle,
12}
13
14unsafe impl Send for ExtStressSolver {}
15unsafe impl Sync for ExtStressSolver {}
16
17impl ExtStressSolver {
18 pub fn new(nodes: &[NodeDesc], bonds: &[BondDesc], settings: &SolverSettings) -> Option<Self> {
20 if nodes.is_empty() || bonds.is_empty() {
21 return None;
22 }
23
24 let ffi_nodes: Vec<ffi::FfiExtStressNodeDesc> = nodes
25 .iter()
26 .map(|n| ffi::FfiExtStressNodeDesc {
27 centroid: n.centroid,
28 mass: n.mass,
29 volume: n.volume,
30 })
31 .collect();
32
33 let ffi_bonds: Vec<ffi::FfiExtStressBondDesc> = bonds
34 .iter()
35 .map(|b| ffi::FfiExtStressBondDesc {
36 centroid: b.centroid,
37 normal: b.normal,
38 area: b.area,
39 node0: b.node0,
40 node1: b.node1,
41 })
42 .collect();
43
44 let ffi_settings = to_ffi_settings(settings);
45
46 let handle = unsafe {
47 ffi::ext_stress_solver_create(
48 ffi_nodes.as_ptr(),
49 ffi_nodes.len() as u32,
50 ffi_bonds.as_ptr(),
51 ffi_bonds.len() as u32,
52 &ffi_settings,
53 )
54 };
55
56 if handle.is_null() {
57 None
58 } else {
59 Some(Self { handle })
60 }
61 }
62
63 pub fn set_settings(&mut self, settings: &SolverSettings) {
65 let ffi_settings = to_ffi_settings(settings);
66 unsafe { ffi::ext_stress_solver_set_settings(self.handle, &ffi_settings) }
67 }
68
69 pub fn reset(&mut self) {
71 unsafe { ffi::ext_stress_solver_reset(self.handle) }
72 }
73
74 pub fn add_force(&mut self, node_index: u32, position: Vec3, force: Vec3, mode: ForceMode) {
76 unsafe {
77 ffi::ext_stress_solver_add_force(
78 self.handle,
79 node_index,
80 &position,
81 &force,
82 mode as u32,
83 )
84 }
85 }
86
87 pub fn add_gravity(&mut self, gravity: Vec3) {
89 unsafe { ffi::ext_stress_solver_add_gravity(self.handle, &gravity) }
90 }
91
92 pub fn add_actor_gravity(&mut self, actor_index: u32, gravity: Vec3) -> bool {
94 unsafe { ffi::ext_stress_solver_add_actor_gravity(self.handle, actor_index, &gravity) != 0 }
95 }
96
97 pub fn update(&mut self) {
99 unsafe { ffi::ext_stress_solver_update(self.handle) }
100 }
101
102 pub fn overstressed_bond_count(&self) -> u32 {
104 unsafe { ffi::ext_stress_solver_overstressed_bond_count(self.handle) }
105 }
106
107 pub fn converged(&self) -> bool {
109 unsafe { ffi::ext_stress_solver_converged(self.handle) != 0 }
110 }
111
112 pub fn linear_error(&self) -> f32 {
114 unsafe { ffi::ext_stress_solver_get_linear_error(self.handle) }
115 }
116
117 pub fn angular_error(&self) -> f32 {
119 unsafe { ffi::ext_stress_solver_get_angular_error(self.handle) }
120 }
121
122 pub fn actor_count(&self) -> u32 {
124 unsafe { ffi::ext_stress_solver_actor_count(self.handle) }
125 }
126
127 pub fn node_count(&self) -> u32 {
129 unsafe { ffi::ext_stress_solver_graph_node_count(self.handle) }
130 }
131
132 pub fn bond_count(&self) -> u32 {
134 unsafe { ffi::ext_stress_solver_bond_count(self.handle) }
135 }
136
137 pub fn actors(&self) -> Vec<Actor> {
139 let actor_count = self.actor_count();
140 if actor_count == 0 {
141 return Vec::new();
142 }
143 let node_count = self.node_count();
144
145 let mut actor_buffer = vec![
146 ffi::FfiExtStressActor {
147 actor_index: u32::MAX,
148 nodes: std::ptr::null(),
149 node_count: 0,
150 };
151 actor_count as usize
152 ];
153 let mut nodes_buffer = vec![0u32; node_count as usize];
154 let mut out_actor_count = 0u32;
155 let mut out_node_count = 0u32;
156
157 unsafe {
158 ffi::ext_stress_solver_collect_actors(
159 self.handle,
160 actor_buffer.as_mut_ptr(),
161 actor_count,
162 nodes_buffer.as_mut_ptr(),
163 node_count,
164 &mut out_actor_count,
165 &mut out_node_count,
166 );
167 }
168
169 let mut result = Vec::with_capacity(out_actor_count as usize);
170 for i in 0..out_actor_count as usize {
171 let ffi_actor = &actor_buffer[i];
172 let nodes = if !ffi_actor.nodes.is_null() && ffi_actor.node_count > 0 {
173 let offset = unsafe { ffi_actor.nodes.offset_from(nodes_buffer.as_ptr()) } as usize;
174 nodes_buffer[offset..offset + ffi_actor.node_count as usize].to_vec()
175 } else {
176 Vec::new()
177 };
178 result.push(Actor {
179 actor_index: ffi_actor.actor_index,
180 nodes,
181 });
182 }
183 result
184 }
185
186 pub fn generate_fracture_commands(&self) -> Vec<FractureCommand> {
188 let actor_count = self.actor_count();
189 let bond_count = self.bond_count();
190 if actor_count == 0 || bond_count == 0 {
191 return Vec::new();
192 }
193
194 let mut command_buffer = vec![
195 ffi::FfiExtStressFractureCommands {
196 actor_index: u32::MAX,
197 bond_fractures: std::ptr::null_mut(),
198 bond_fracture_count: 0,
199 };
200 actor_count as usize
201 ];
202 let mut bond_buffer = vec![ffi::FfiExtStressBondFracture::default(); bond_count as usize];
203 let mut out_command_count = 0u32;
204 let mut out_bond_count = 0u32;
205
206 unsafe {
207 ffi::ext_stress_solver_generate_fracture_commands_per_actor(
208 self.handle,
209 command_buffer.as_mut_ptr(),
210 actor_count,
211 bond_buffer.as_mut_ptr(),
212 bond_count,
213 &mut out_command_count,
214 &mut out_bond_count,
215 );
216 }
217
218 let mut result = Vec::with_capacity(out_command_count as usize);
219 for i in 0..out_command_count as usize {
220 let cmd = &command_buffer[i];
221 let fractures = if !cmd.bond_fractures.is_null() && cmd.bond_fracture_count > 0 {
222 let offset =
223 unsafe { cmd.bond_fractures.offset_from(bond_buffer.as_ptr()) } as usize;
224 bond_buffer[offset..offset + cmd.bond_fracture_count as usize]
225 .iter()
226 .map(|f| BondFracture {
227 userdata: f.userdata,
228 node_index0: f.node_index0,
229 node_index1: f.node_index1,
230 health: f.health,
231 })
232 .collect()
233 } else {
234 Vec::new()
235 };
236 result.push(FractureCommand {
237 actor_index: cmd.actor_index,
238 bond_fractures: fractures,
239 });
240 }
241 result
242 }
243
244 pub fn apply_fracture_commands(&mut self, commands: &[FractureCommand]) -> Vec<SplitEvent> {
246 if commands.is_empty() {
247 return Vec::new();
248 }
249
250 let total_bonds: usize = commands.iter().map(|c| c.bond_fractures.len()).sum();
252 let mut flat_bonds = vec![ffi::FfiExtStressBondFracture::default(); total_bonds];
253 let mut ffi_commands = Vec::with_capacity(commands.len());
254 let mut offset = 0usize;
255
256 for cmd in commands {
257 for (i, f) in cmd.bond_fractures.iter().enumerate() {
258 flat_bonds[offset + i] = ffi::FfiExtStressBondFracture {
259 userdata: f.userdata,
260 node_index0: f.node_index0,
261 node_index1: f.node_index1,
262 health: f.health,
263 };
264 }
265 ffi_commands.push(ffi::FfiExtStressFractureCommands {
266 actor_index: cmd.actor_index,
267 bond_fractures: if cmd.bond_fractures.is_empty() {
268 std::ptr::null_mut()
269 } else {
270 unsafe { flat_bonds.as_mut_ptr().add(offset) }
271 },
272 bond_fracture_count: cmd.bond_fractures.len() as u32,
273 });
274 offset += cmd.bond_fractures.len();
275 }
276
277 let node_count = self.node_count() as usize;
279 let max_events = commands.len();
280 let max_children = node_count;
281
282 let mut events_buffer = vec![
283 ffi::FfiExtStressSplitEvent {
284 parent_actor_index: u32::MAX,
285 children: std::ptr::null_mut(),
286 child_count: 0,
287 };
288 max_events
289 ];
290 let mut child_buffer = vec![
291 ffi::FfiExtStressActor {
292 actor_index: u32::MAX,
293 nodes: std::ptr::null(),
294 node_count: 0,
295 };
296 max_children
297 ];
298 let mut nodes_buffer = vec![0u32; node_count];
299 let mut out_event_count = 0u32;
300 let mut out_child_count = 0u32;
301 let mut out_node_count = 0u32;
302
303 unsafe {
304 ffi::ext_stress_solver_apply_fracture_commands(
305 self.handle,
306 ffi_commands.as_ptr(),
307 ffi_commands.len() as u32,
308 events_buffer.as_mut_ptr(),
309 max_events as u32,
310 child_buffer.as_mut_ptr(),
311 max_children as u32,
312 &mut out_event_count,
313 &mut out_child_count,
314 nodes_buffer.as_mut_ptr(),
315 node_count as u32,
316 &mut out_node_count,
317 );
318 }
319
320 let mut result = Vec::with_capacity(out_event_count as usize);
322 for i in 0..out_event_count as usize {
323 let evt = &events_buffer[i];
324 let mut children = Vec::with_capacity(evt.child_count as usize);
325
326 if !evt.children.is_null() && evt.child_count > 0 {
327 let child_offset =
328 unsafe { evt.children.offset_from(child_buffer.as_ptr()) } as usize;
329 for ci in 0..evt.child_count as usize {
330 let child = &child_buffer[child_offset + ci];
331 let nodes = if !child.nodes.is_null() && child.node_count > 0 {
332 let node_off =
333 unsafe { child.nodes.offset_from(nodes_buffer.as_ptr()) } as usize;
334 nodes_buffer[node_off..node_off + child.node_count as usize].to_vec()
335 } else {
336 Vec::new()
337 };
338 children.push(SplitChild {
339 actor_index: child.actor_index,
340 nodes,
341 });
342 }
343 }
344
345 result.push(SplitEvent {
346 parent_actor_index: evt.parent_actor_index,
347 children,
348 });
349 }
350 result
351 }
352
353 pub fn get_excess_forces(&self, actor_index: u32, com: Vec3) -> Option<(Vec3, Vec3)> {
356 let mut force = Vec3::ZERO;
357 let mut torque = Vec3::ZERO;
358 let ok = unsafe {
359 ffi::ext_stress_solver_get_excess_forces(
360 self.handle,
361 actor_index,
362 &com,
363 &mut force,
364 &mut torque,
365 )
366 };
367 if ok != 0 {
368 Some((force, torque))
369 } else {
370 None
371 }
372 }
373}
374
375impl Drop for ExtStressSolver {
376 fn drop(&mut self) {
377 unsafe { ffi::ext_stress_solver_destroy(self.handle) }
378 }
379}
380
381fn to_ffi_settings(s: &SolverSettings) -> ffi::FfiExtStressSolverSettingsDesc {
382 ffi::FfiExtStressSolverSettingsDesc {
383 max_solver_iterations_per_frame: s.max_solver_iterations_per_frame,
384 graph_reduction_level: s.graph_reduction_level,
385 compression_elastic_limit: s.compression_elastic_limit,
386 compression_fatal_limit: s.compression_fatal_limit,
387 tension_elastic_limit: s.tension_elastic_limit,
388 tension_fatal_limit: s.tension_fatal_limit,
389 shear_elastic_limit: s.shear_elastic_limit,
390 shear_fatal_limit: s.shear_fatal_limit,
391 }
392}