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);