Skip to main content

dynamis_abi/
soft.rs

1use crate::constant::{
2    ELEMENT_AREA, ELEMENT_BEND, ELEMENT_BROKEN, ELEMENT_DISTANCE, ELEMENT_KIND_MASK,
3    ELEMENT_PARTICLES, ELEMENT_VOLUME, NO_BODY, NO_SLOT,
4};
5use crate::{SoftAttachmentRecord, SoftBodyRecord, SoftElementRecord, SoftParticleRecord};
6use dynamis_model::{SoftElement, SoftElementKind, SoftElementState};
7
8pub struct SoftParticleInit {
9    pub position: [f32; 3],
10    pub prev_position: [f32; 3],
11    pub velocity: [f32; 3],
12    pub radius: f32,
13    pub inverse_mass: f32,
14    pub friction: f32,
15    pub support: f32,
16    pub rest_spacing: f32,
17    pub neighbour_offset: u32,
18    pub neighbour_count: u32,
19    pub owner: u32,
20    pub generation: u32,
21}
22
23impl SoftParticleRecord {
24    pub fn build(init: SoftParticleInit) -> Self {
25        Self {
26            position: [
27                init.position[0],
28                init.position[1],
29                init.position[2],
30                init.radius,
31            ],
32            prev_position: [
33                init.prev_position[0],
34                init.prev_position[1],
35                init.prev_position[2],
36                init.inverse_mass,
37            ],
38            velocity: [
39                init.velocity[0],
40                init.velocity[1],
41                init.velocity[2],
42                init.friction,
43            ],
44            support: init.support,
45            rest_spacing: init.rest_spacing,
46            neighbour_offset: init.neighbour_offset,
47            neighbour_count: init.neighbour_count,
48            owner: init.owner,
49            generation: init.generation,
50            _wgsl_pad0: [0; 8],
51        }
52    }
53
54    pub const fn cleared() -> Self {
55        Self {
56            position: [0.0; 4],
57            prev_position: [0.0; 4],
58            velocity: [0.0; 4],
59            support: 0.0,
60            rest_spacing: 0.0,
61            neighbour_offset: NO_SLOT,
62            neighbour_count: 0,
63            owner: NO_BODY,
64            generation: 0,
65            _wgsl_pad0: [0; 8],
66        }
67    }
68
69    pub const fn radius(&self) -> f32 {
70        self.position[3]
71    }
72
73    pub const fn inverse_mass(&self) -> f32 {
74        self.prev_position[3]
75    }
76
77    pub const fn friction(&self) -> f32 {
78        self.velocity[3]
79    }
80
81    pub const fn support(&self) -> f32 {
82        self.support
83    }
84
85    pub const fn rest_spacing(&self) -> f32 {
86        self.rest_spacing
87    }
88
89    pub const fn carries_continuum(&self) -> bool {
90        self.support > 0.0
91    }
92}
93
94impl SoftBodyRecord {
95    pub const fn awake() -> Self {
96        Self {
97            sleep_timer: 0.0,
98            sleeping: 0,
99            moving: 0,
100            wake: 0,
101        }
102    }
103
104    pub const fn cleared() -> Self {
105        Self {
106            sleeping: 1,
107            ..Self::awake()
108        }
109    }
110}
111
112pub struct SoftAttachmentInit {
113    pub particle: u32,
114    pub body_id: u32,
115    pub generation: u32,
116    pub local: [f32; 3],
117}
118
119impl SoftAttachmentRecord {
120    pub fn build(init: SoftAttachmentInit) -> Self {
121        Self {
122            local: init.local,
123            particle: init.particle,
124            body_id: init.body_id,
125            generation: init.generation,
126            _wgsl_pad0: [0; 8],
127        }
128    }
129
130    pub const fn cleared() -> Self {
131        Self {
132            local: [0.0; 3],
133            particle: NO_SLOT,
134            body_id: NO_BODY,
135            generation: 0,
136            _wgsl_pad0: [0; 8],
137        }
138    }
139}
140
141pub struct SoftElementInit {
142    pub kind: u32,
143    pub particles: [u32; ELEMENT_PARTICLES as usize],
144    pub rest: f32,
145    pub compliance: f32,
146    pub yield_strain: f32,
147    pub break_strain: f32,
148    pub plastic_flow: f32,
149}
150
151impl SoftElementRecord {
152    pub fn build(init: SoftElementInit) -> Self {
153        Self {
154            particles: init.particles,
155            rest: init.rest,
156            compliance: init.compliance,
157            lambda: 0.0,
158            kind: init.kind,
159            yield_strain: init.yield_strain,
160            break_strain: init.break_strain,
161            plastic_flow: init.plastic_flow,
162        }
163    }
164
165    pub const fn cleared() -> Self {
166        Self {
167            particles: [NO_SLOT; ELEMENT_PARTICLES as usize],
168            rest: 0.0,
169            compliance: 0.0,
170            lambda: 0.0,
171            kind: ELEMENT_DISTANCE,
172            yield_strain: f32::INFINITY,
173            break_strain: f32::INFINITY,
174            plastic_flow: 0.0,
175        }
176    }
177
178    pub fn state(&self) -> SoftElementState {
179        SoftElementState::new(
180            element_kind(self.kind),
181            self.particles,
182            self.rest,
183            self.kind & ELEMENT_BROKEN != 0,
184        )
185    }
186}
187
188fn element_kind(kind: u32) -> SoftElementKind {
189    match kind & ELEMENT_KIND_MASK {
190        ELEMENT_DISTANCE => SoftElementKind::Distance,
191        ELEMENT_AREA => SoftElementKind::Area,
192        ELEMENT_BEND => SoftElementKind::Bend,
193        ELEMENT_VOLUME => SoftElementKind::Volume,
194        kind => panic!("soft element kind {kind} is outside the material table"),
195    }
196}
197
198const _: () = assert!(ELEMENT_PARTICLES as usize == SoftElement::PARTICLES);
199const _: () = assert!(SoftElement::UNUSED == NO_SLOT);
200const _: () = assert!(SoftElementKind::Distance as u32 == ELEMENT_DISTANCE);
201const _: () = assert!(SoftElementKind::Area as u32 == ELEMENT_AREA);
202const _: () = assert!(SoftElementKind::Bend as u32 == ELEMENT_BEND);
203const _: () = assert!(SoftElementKind::Volume as u32 == ELEMENT_VOLUME);