Skip to main content

anput_physics/
components.rs

1use crate::{PhysicsAccessView, Scalar};
2use anput::{
3    entity::Entity,
4    query::TypedLookupFetch,
5    world::{Relation, World},
6};
7use serde::{Deserialize, Serialize};
8use vek::{Mat4, Quaternion, Vec3};
9
10#[derive(Clone)]
11pub struct BodyAccessInfo {
12    pub entity: Entity,
13    pub view: PhysicsAccessView,
14}
15
16impl BodyAccessInfo {
17    pub fn new(entity: Entity, view: PhysicsAccessView) -> Self {
18        Self { entity, view }
19    }
20
21    pub fn of_world(entity: Entity, world: &World) -> Self {
22        Self::new(entity, PhysicsAccessView::new(world))
23    }
24
25    pub fn particles<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING> + 'a>(
26        &'a self,
27    ) -> impl Iterator<Item = Fetch::Value> + 'a {
28        self.view
29            .entity::<LOCKING, &Relation<BodyParticleRelation>>(self.entity)
30            .map(|relations| self.view.lookup::<LOCKING, Fetch>(relations.entities()))
31            .into_iter()
32            .flatten()
33    }
34
35    pub fn world_space_particles<
36        'a,
37        const LOCKING: bool,
38        Fetch: TypedLookupFetch<'a, LOCKING> + 'a,
39    >(
40        &'a self,
41    ) -> impl Iterator<Item = (Mat4<Scalar>, Fetch::Value)> + 'a {
42        self.view
43            .entity::<LOCKING, &Relation<BodyParticleRelation>>(self.entity)
44            .map(|relations| {
45                self.view
46                    .lookup::<LOCKING, (&Position, Option<&Rotation>, Fetch)>(relations.entities())
47                    .map(|(position, rotation, value)| {
48                        let matrix = rotation
49                            .map(|rotation| Mat4::from(rotation.current))
50                            .unwrap_or_default()
51                            * Mat4::translation_3d(position.current);
52                        (matrix, value)
53                    })
54            })
55            .into_iter()
56            .flatten()
57    }
58
59    pub fn density_fields<'a, const LOCKING: bool, Fetch: TypedLookupFetch<'a, LOCKING> + 'a>(
60        &'a self,
61    ) -> impl Iterator<Item = Fetch::Value> + 'a {
62        self.view
63            .entity::<LOCKING, &Relation<BodyDensityFieldRelation>>(self.entity)
64            .map(|relations| self.view.lookup::<LOCKING, Fetch>(relations.entities()))
65            .into_iter()
66            .flatten()
67    }
68}
69
70pub struct PhysicsBody;
71pub struct PhysicsParticle;
72pub struct BodyParticleRelation;
73pub struct BodyDensityFieldRelation;
74pub struct ParticleConstraintRelation;
75pub struct BodyParentRelation;
76
77#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
78pub struct Mass {
79    value: Scalar,
80    inverse: Scalar,
81}
82
83impl Mass {
84    pub fn new(value: Scalar) -> Self {
85        Self {
86            value,
87            inverse: if value != 0.0 { 1.0 / value } else { 0.0 },
88        }
89    }
90
91    pub fn new_inverse(inverse: Scalar) -> Self {
92        Self {
93            value: if inverse != 0.0 { 1.0 / inverse } else { 0.0 },
94            inverse,
95        }
96    }
97
98    pub fn value(&self) -> Scalar {
99        self.value
100    }
101
102    pub fn inverse(&self) -> Scalar {
103        self.inverse
104    }
105}
106
107impl PartialEq for Mass {
108    fn eq(&self, other: &Self) -> bool {
109        self.value == other.value
110    }
111}
112
113#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
114pub struct Position {
115    pub current: Vec3<Scalar>,
116    previous: Vec3<Scalar>,
117}
118
119impl Position {
120    pub fn new(current: impl Into<Vec3<Scalar>>) -> Self {
121        let current = current.into();
122        Self {
123            current,
124            previous: current,
125        }
126    }
127
128    pub fn previous(&self) -> Vec3<Scalar> {
129        self.previous
130    }
131
132    pub fn change(&self) -> Vec3<Scalar> {
133        self.current - self.previous
134    }
135
136    pub fn cache_current_as_previous(&mut self) {
137        self.previous = self.current;
138    }
139}
140
141impl PartialEq for Position {
142    fn eq(&self, other: &Self) -> bool {
143        self.current == other.current
144    }
145}
146
147#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)]
148pub struct Rotation {
149    pub current: Quaternion<Scalar>,
150    previous: Quaternion<Scalar>,
151}
152
153impl Rotation {
154    pub fn new(current: impl Into<Quaternion<Scalar>>) -> Self {
155        let current = current.into();
156        Self {
157            current,
158            previous: current,
159        }
160    }
161
162    pub fn previous(&self) -> Quaternion<Scalar> {
163        self.previous
164    }
165
166    pub fn change(&self) -> Quaternion<Scalar> {
167        self.current * self.previous.conjugate()
168    }
169
170    pub fn cache_current_as_previous(&mut self) {
171        self.previous = self.current;
172    }
173}
174
175#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)]
176#[repr(transparent)]
177pub struct LinearVelocity {
178    pub value: Vec3<Scalar>,
179}
180
181impl LinearVelocity {
182    pub fn new(value: impl Into<Vec3<Scalar>>) -> Self {
183        Self {
184            value: value.into(),
185        }
186    }
187}
188
189#[derive(Debug, Default, Clone, Copy, PartialEq, Serialize, Deserialize)]
190#[repr(transparent)]
191pub struct AngularVelocity {
192    pub value: Vec3<Scalar>,
193}
194
195impl AngularVelocity {
196    pub fn new(value: impl Into<Vec3<Scalar>>) -> Self {
197        Self {
198            value: value.into(),
199        }
200    }
201}
202
203#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
204pub struct ExternalForces {
205    pub force: Vec3<Scalar>,
206    pub torque: Vec3<Scalar>,
207    pub linear_impulse: Vec3<Scalar>,
208    pub angular_impulse: Vec3<Scalar>,
209}
210
211impl ExternalForces {
212    pub fn accumulate_force(&mut self, force: Vec3<Scalar>) {
213        self.force += force;
214    }
215
216    pub fn accumulate_torque(&mut self, torque: Vec3<Scalar>) {
217        self.torque += torque;
218    }
219
220    pub fn accumulate_linear_impulse(&mut self, impulse: Vec3<Scalar>) {
221        self.linear_impulse += impulse;
222    }
223
224    pub fn accumulate_angular_impulse(&mut self, impulse: Vec3<Scalar>) {
225        self.angular_impulse += impulse;
226    }
227
228    pub fn clear_continuous(&mut self) {
229        self.force = Vec3::zero();
230        self.torque = Vec3::zero();
231    }
232
233    pub fn clear_instantaneous(&mut self) {
234        self.linear_impulse = Vec3::zero();
235        self.angular_impulse = Vec3::zero();
236    }
237
238    pub fn clear(&mut self) {
239        self.clear_continuous();
240        self.clear_instantaneous();
241    }
242}
243
244#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
245pub struct Gravity {
246    pub value: Vec3<Scalar>,
247}
248
249#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
250pub struct BodyMaterial {
251    pub friction: Scalar,
252    pub restitution: Scalar,
253}
254
255impl Default for BodyMaterial {
256    fn default() -> Self {
257        Self {
258            friction: 0.5,
259            restitution: 0.5,
260        }
261    }
262}
263
264#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
265pub struct ParticleMaterial {
266    pub linear_damping: Scalar,
267    pub angular_damping: Scalar,
268    pub linear_rest_threshold: Scalar,
269    pub angular_rest_threshold: Scalar,
270}
271
272impl Default for ParticleMaterial {
273    fn default() -> Self {
274        Self {
275            linear_damping: 0.9,
276            angular_damping: 0.9,
277            linear_rest_threshold: 0.05,
278            angular_rest_threshold: 0.05,
279        }
280    }
281}