euv_engine/particle/
impl.rs1use super::*;
2
3impl ParticleRng {
5 pub fn with_seed(seed: u64) -> ParticleRng {
16 if seed == 0 {
17 ParticleRng::new(PARTICLE_DEFAULT_RNG_SEED)
18 } else {
19 ParticleRng::new(seed)
20 }
21 }
22
23 pub fn next_u64(&mut self) -> u64 {
29 let mut state: u64 = self.get_state();
30 state ^= state >> 12;
31 state ^= state << 25;
32 state ^= state >> 27;
33 self.set_state(state);
34 state.wrapping_mul(0x2545_F491_4F6C_DD1D)
35 }
36
37 pub fn next_f64(&mut self) -> f64 {
43 (self.next_u64() >> 11) as f64 / (1u64 << 53) as f64
44 }
45
46 pub fn range(&mut self, min: f64, max: f64) -> f64 {
57 min + (max - min) * self.next_f64()
58 }
59}
60
61impl Default for ParticleRng {
63 fn default() -> ParticleRng {
64 ParticleRng::with_seed(PARTICLE_DEFAULT_RNG_SEED)
65 }
66}
67
68impl Default for ParticleConfig {
70 fn default() -> ParticleConfig {
71 ParticleConfig {
72 emission_rate: PARTICLE_DEFAULT_EMISSION_RATE,
73 max_particles: PARTICLE_DEFAULT_MAX_COUNT,
74 lifetime_min: PARTICLE_DEFAULT_LIFETIME_MIN,
75 lifetime_max: PARTICLE_DEFAULT_LIFETIME_MAX,
76 speed_min: PARTICLE_DEFAULT_SPEED_MIN,
77 speed_max: PARTICLE_DEFAULT_SPEED_MAX,
78 angle: PARTICLE_DEFAULT_ANGLE,
79 spread: PARTICLE_DEFAULT_SPREAD,
80 gravity: Vector2D::zero(),
81 color_start: Color::white(),
82 color_end: Color::transparent(),
83 size_start: PARTICLE_DEFAULT_SIZE_START,
84 size_end: PARTICLE_DEFAULT_SIZE_END,
85 }
86 }
87}
88
89impl ParticleEmitter {
91 pub fn create(position: Vector2D, config: ParticleConfig) -> ParticleEmitter {
102 let mut emitter: ParticleEmitter = ParticleEmitter::new(position, config);
103 emitter.set_active(true);
104 emitter
105 }
106
107 pub fn with_defaults(position: Vector2D) -> ParticleEmitter {
118 ParticleEmitter::create(position, ParticleConfig::default())
119 }
120
121 pub fn update(&mut self, delta_time: f64) {
129 let delta_time: f64 = delta_time.max(0.0);
130 if self.get_active() {
131 *self.get_mut_emit_accumulator() += self.get_config().get_emission_rate() * delta_time;
132 let mut spawn_count: usize = self.get_emit_accumulator() as usize;
133 let capacity: usize = self
134 .get_config()
135 .get_max_particles()
136 .saturating_sub(self.get_particles().len());
137 spawn_count = spawn_count.min(capacity);
138 *self.get_mut_emit_accumulator() -= spawn_count as f64;
139 for _ in 0..spawn_count {
140 self.spawn_particle();
141 }
142 }
143 let gravity: Vector2D = self.get_config().get_gravity();
144 for particle in self.get_mut_particles().iter_mut() {
145 *particle.get_mut_velocity() += gravity.scaled(delta_time);
146 let velocity: Vector2D = particle.get_velocity();
147 *particle.get_mut_position() += velocity.scaled(delta_time);
148 *particle.get_mut_age() += delta_time;
149 }
150 self.get_mut_particles()
151 .retain(|particle: &Particle| particle.get_age() < particle.get_lifetime());
152 }
153
154 pub fn burst(&mut self, count: usize) {
161 let capacity: usize = self
162 .get_config()
163 .get_max_particles()
164 .saturating_sub(self.get_particles().len());
165 for _ in 0..count.min(capacity) {
166 self.spawn_particle();
167 }
168 }
169
170 pub fn render(&self, draw_list: &mut DrawList) {
179 let config: ParticleConfig = self.get_config();
180 for particle in self.get_particles().iter() {
181 let t: f64 = if particle.get_lifetime() > 0.0 {
182 (particle.get_age() / particle.get_lifetime()).min(1.0)
183 } else {
184 1.0
185 };
186 let color: Color = config.get_color_start().lerp(config.get_color_end(), t);
187 let radius: f64 = Numeric::lerp(config.get_size_start(), config.get_size_end(), t);
188 if radius <= 0.0 || color.get_alpha() <= 0.0 {
189 continue;
190 }
191 draw_list.fill_circle(particle.get_position(), radius, color);
192 }
193 }
194
195 pub fn alive_count(&self) -> usize {
201 self.get_particles().len()
202 }
203
204 pub fn clear(&mut self) {
206 self.get_mut_particles().clear();
207 self.set_emit_accumulator(0.0);
208 }
209
210 fn spawn_particle(&mut self) {
213 let config: ParticleConfig = self.get_config();
214 let half_spread: f64 = config.get_spread() / 2.0;
215 let angle: f64 = config.get_angle() + self.get_mut_rng().range(-half_spread, half_spread);
216 let speed: f64 = self
217 .get_mut_rng()
218 .range(config.get_speed_min(), config.get_speed_max());
219 let lifetime: f64 = self
220 .get_mut_rng()
221 .range(config.get_lifetime_min(), config.get_lifetime_max())
222 .max(EPSILON);
223 let position: Vector2D = self.get_position();
224 let particle: Particle = Particle::new(
225 position,
226 Vector2D::from_angle(angle).scaled(speed),
227 0.0,
228 lifetime,
229 );
230 self.get_mut_particles().push(particle);
231 }
232}
233
234impl Updatable for ParticleEmitter {
238 fn update(&mut self, delta_time: f64) {
239 ParticleEmitter::update(self, delta_time);
240 }
241}