vox_geometry_rust/
point_particle_emitter2.rs1use crate::matrix2x2::*;
10use crate::vector2::Vector2D;
11use crate::particle_emitter2::*;
12use std::sync::{RwLock, Arc};
13use rand::prelude::*;
14use rand_pcg::{Pcg64, Lcg128Xsl64};
15
16pub type OnBeginUpdateCallback = fn(&mut PointParticleEmitter2, f64, f64);
23
24pub struct PointParticleEmitter2 {
31 _rng: Lcg128Xsl64,
32 _first_frame_time_in_seconds: f64,
33 _number_of_emitted_particles: usize,
34
35 _max_number_of_new_particles_per_second: usize,
36 _max_number_of_particles: usize,
37
38 _origin: Vector2D,
39 _direction: Vector2D,
40 _speed: f64,
41 _spread_angle_in_radians: f64,
42
43 _emitter_data: ParticleEmitter2Data,
44 _on_begin_update_callback: Option<OnBeginUpdateCallback>,
45}
46
47impl PointParticleEmitter2 {
48 pub fn new(origin: &Vector2D,
62 direction: &Vector2D,
63 speed: f64,
64 spread_angle_in_degrees: f64,
65 max_num_of_new_particles_per_sec: Option<usize>,
66 max_num_of_particles: Option<usize>,
67 seed: Option<u64>) -> PointParticleEmitter2 {
68 return PointParticleEmitter2 {
69 _rng: Pcg64::seed_from_u64(seed.unwrap_or(0)),
70 _first_frame_time_in_seconds: 0.0,
71 _number_of_emitted_particles: 0,
72 _max_number_of_new_particles_per_second: max_num_of_new_particles_per_sec.unwrap_or(1),
73 _max_number_of_particles: max_num_of_particles.unwrap_or(usize::MAX),
74 _origin: *origin,
75 _direction: *direction,
76 _speed: speed,
77 _spread_angle_in_radians: crate::math_utils::degrees_to_radians(spread_angle_in_degrees),
78 _emitter_data: ParticleEmitter2Data::new(),
79 _on_begin_update_callback: None,
80 };
81 }
82
83 pub fn builder() -> Builder {
85 return Builder::new();
86 }
87
88 pub fn max_number_of_new_particles_per_second(&self) -> usize {
90 return self._max_number_of_new_particles_per_second;
91 }
92
93 pub fn set_max_number_of_new_particles_per_second(&mut self, rate: usize) {
95 self._max_number_of_new_particles_per_second = rate;
96 }
97
98 pub fn max_number_of_particles(&self) -> usize {
100 return self._max_number_of_particles;
101 }
102
103 pub fn set_max_number_of_particles(&mut self, max_number_of_particles: usize) {
105 self._max_number_of_particles = max_number_of_particles;
106 }
107
108 fn emit(&mut self, new_positions: &mut Vec<Vector2D>,
109 new_velocities: &mut Vec<Vector2D>,
110 max_new_number_of_particles: usize) {
111 for _ in 0..max_new_number_of_particles {
112 let new_angle_in_radian = (self.random() - 0.5) * self._spread_angle_in_radians;
113 let rotation_matrix = Matrix2x2D::make_rotation_matrix(new_angle_in_radian);
114
115 new_positions.push(self._origin);
116 new_velocities.push((rotation_matrix * self._direction) * self._speed);
117 }
118 }
119
120 fn random(&mut self) -> f64 {
121 return self._rng.gen_range(0.0..1.0);
122 }
123
124 pub fn set_on_begin_update_callback(&mut self, callback: OnBeginUpdateCallback) {
135 self._on_begin_update_callback = Some(callback);
136 }
137}
138
139impl ParticleEmitter2 for PointParticleEmitter2 {
140 fn update(&mut self, current_time_in_seconds: f64, time_interval_in_seconds: f64) where Self: Sized {
141 match self._on_begin_update_callback {
142 None => {}
143 Some(callback) => {
144 callback(self, current_time_in_seconds,
145 time_interval_in_seconds);
146 }
147 }
148
149 self.on_update(current_time_in_seconds, time_interval_in_seconds);
150 }
151
152 fn on_update(&mut self, current_time_in_seconds: f64, time_interval_in_seconds: f64) {
153 let particles;
154 match self.target() {
155 None => {
156 return;
157 }
158 Some(target) => {
159 particles = target.clone();
160 }
161 }
162
163 if self._number_of_emitted_particles == 0 {
164 self._first_frame_time_in_seconds = current_time_in_seconds;
165 }
166
167 let elapsed_time_in_seconds = current_time_in_seconds - self._first_frame_time_in_seconds;
168
169 let mut new_max_total_number_of_emitted_particles = (
170 f64::ceil((elapsed_time_in_seconds + time_interval_in_seconds)
171 * self._max_number_of_new_particles_per_second as f64)) as usize;
172 new_max_total_number_of_emitted_particles = usize::min(new_max_total_number_of_emitted_particles,
173 self._max_number_of_particles);
174 let max_number_of_new_particles
175 = new_max_total_number_of_emitted_particles - self._number_of_emitted_particles;
176
177 if max_number_of_new_particles > 0 {
178 let mut candidate_positions: Vec<Vector2D> = Vec::new();
179 let mut candidate_velocities: Vec<Vector2D> = Vec::new();
180 let mut new_positions: Vec<Vector2D> = Vec::new();
181 let mut new_velocities: Vec<Vector2D> = Vec::new();
182
183 self.emit(
184 &mut candidate_positions,
185 &mut candidate_velocities,
186 max_number_of_new_particles);
187
188 new_positions.append(&mut candidate_positions);
189 new_velocities.append(&mut candidate_velocities);
190
191 particles.write().unwrap().add_particles(&new_positions, Some(&new_velocities), None);
192
193 self._number_of_emitted_particles += new_positions.len();
194 }
195 }
196
197 fn view(&self) -> &ParticleEmitter2Data {
198 return &self._emitter_data;
199 }
200
201 fn view_mut(&mut self) -> &mut ParticleEmitter2Data {
202 return &mut self._emitter_data;
203 }
204}
205
206pub type PointParticleEmitter2Ptr = Arc<RwLock<PointParticleEmitter2>>;
208
209pub struct Builder {
213 _max_number_of_new_particles_per_second: usize,
214 _max_number_of_particles: usize,
215 _origin: Vector2D,
216 _direction: Vector2D,
217 _speed: f64,
218 _spread_angle_in_degrees: f64,
219 _seed: u64,
220}
221
222impl Builder {
223 pub fn with_origin(&mut self, origin: &Vector2D) -> &mut Self {
225 self._origin = *origin;
226 return self;
227 }
228
229 pub fn with_direction(&mut self, direction: &Vector2D) -> &mut Self {
231 self._direction = *direction;
232 return self;
233 }
234
235 pub fn with_speed(&mut self, speed: f64) -> &mut Self {
237 self._speed = speed;
238 return self;
239 }
240
241 pub fn with_spread_angle_in_degrees(&mut self, spread_angle_in_degrees: f64) -> &mut Self {
243 self._spread_angle_in_degrees = spread_angle_in_degrees;
244 return self;
245 }
246
247 pub fn with_max_number_of_new_particles_per_second(&mut self,
248 max_num_of_new_particles_per_sec: usize) -> &mut Self {
249 self._max_number_of_new_particles_per_second = max_num_of_new_particles_per_sec;
250 return self;
251 }
252
253 pub fn with_max_number_of_particles(&mut self, max_number_of_particles: usize) -> &mut Self {
255 self._max_number_of_particles = max_number_of_particles;
256 return self;
257 }
258
259 pub fn with_random_seed(&mut self, seed: u64) -> &mut Self {
261 self._seed = seed;
262 return self;
263 }
264
265 pub fn build(&mut self) -> PointParticleEmitter2 {
267 return PointParticleEmitter2::new(&self._origin,
268 &self._direction,
269 self._speed,
270 self._spread_angle_in_degrees,
271 Some(self._max_number_of_new_particles_per_second),
272 Some(self._max_number_of_particles),
273 Some(self._seed));
274 }
275
276 pub fn make_shared(&mut self) -> PointParticleEmitter2Ptr {
278 return PointParticleEmitter2Ptr::new(RwLock::new(self.build()));
279 }
280
281 pub fn new() -> Builder {
283 return Builder {
284 _max_number_of_new_particles_per_second: 1,
285 _max_number_of_particles: usize::MAX,
286 _origin: Vector2D::new_default(),
287 _direction: Vector2D::new(0.0, 1.0),
288 _speed: 1.0,
289 _spread_angle_in_degrees: 90.0,
290 _seed: 0,
291 };
292 }
293}