-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathparticle.rs
More file actions
150 lines (128 loc) · 4.07 KB
/
particle.rs
File metadata and controls
150 lines (128 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#![allow(dead_code)]
#![allow(unused_variables)]
use num_traits::pow;
use oxide_math::commons::vector::*;
use oxide_math::commons::vector3::Vector3;
extern crate generational_arena;
use generational_arena::Arena;
pub struct Particle {
inverse_mass: f32,
damping: f32,
position: Vector3,
pub velocity: Vector3,
force_accum: Vector3,
acceleration: Vector3,
}
impl Particle {
// returns integrated velocity
fn integrate(&mut self, duration: f32) -> Result<Vector3, &str> {
// not to integrate things with infinite mass
if self.inverse_mass <= 0.0f32 {
return Ok(
Vector3 {
x: self.velocity.x,
y: self.velocity.y,
z: self.velocity.z,
});
}
if duration <= 0.0 {
return Err("Cannot integrate with zero duration")
}
// update linear position
self.position.x += self.velocity.scale(duration).x;
self.position.y += self.velocity.scale(duration).y;
self.position.z += self.velocity.scale(duration).z;
// work out the acceleration from the force
let delta = self.force_accum.scale(self.inverse_mass);
let resulting_acc = Vector3 {
x: self.acceleration.x + delta.x,
y: self.acceleration.y + delta.y,
z: self.acceleration.z + delta.z,
};
// update linear velocity from the acceleration
self.velocity.x += resulting_acc.scale(duration).x;
self.velocity.y += resulting_acc.scale(duration).y;
self.velocity.z += resulting_acc.scale(duration).z;
// impose drag
self.velocity = self.velocity.scale(pow(self.damping, duration as usize));
Particle::clear_accumulator(self);
Ok(
Vector3 {
x: self.velocity.x,
y: self.velocity.y,
z: self.velocity.z,
})
}
// Returns inverse of mass
fn set_mass(&mut self, mass: f32) -> Result<f32, &str> {
if mass == 0.0f32 {
return Err("Cannot set zero mass")
}
self.inverse_mass = (1.0f32) / mass;
Ok(self.inverse_mass)
}
// Returns mass of the particle
pub fn get_mass(&self) -> f32 {
if self.inverse_mass == 0.0f32 {
f32::MAX
} else {
1.0f32 / self.inverse_mass
}
}
// Returns the velocity of the particle
pub fn get_velocity(&self) -> Vector3 {
Vector3 {
x: self.velocity.x,
y: self.velocity.y,
z: self.velocity.z,
}
}
pub fn has_finite_mass(&self) -> bool {
self.inverse_mass > 0.0f32
}
fn clear_accumulator(&mut self) {
self.force_accum = Vector3 {
x: 0.0f32,
y: 0.0f32,
z: 0.0f32,
};
}
pub fn add_force(&mut self, force: &Vector3) {
self.force_accum = Vector3 {
x: self.force_accum.x + force.x,
y: self.force_accum.y + force.y,
z: self.force_accum.z + force.z,
};
}
}
// The default particle set containing all the particles added to the world
// Uses arena to avoid ABA problem
pub struct DefaultParticleSet {
particles: Arena<Box<Particle>>,
removed: Vec<DefaultParticleHandle>,
}
impl DefaultParticleSet {
// Creates an empty set
pub fn new() -> Self {
DefaultParticleSet {
particles: Arena::new(),
removed: Vec::new(),
}
}
// Adds a particle to this set
pub fn insert(&mut self, particle: Particle) -> DefaultParticleHandle {
self.particles.insert(Box::new(particle))
}
// Removes a particle from this set
pub fn remove(&mut self, particle_handle: DefaultParticleHandle) -> Option<Box<Particle>> {
let result = self.particles.remove(particle_handle)?;
self.removed.push(particle_handle);
Some(result)
}
}
impl Default for DefaultParticleSet {
fn default() -> Self {
Self::new()
}
}
pub type DefaultParticleHandle = generational_arena::Index;