fyrox_impl/scene/particle_system/emitter/
base.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Base emitter contains properties for all other "derived" emitters.
22
23use crate::{
24    core::{
25        algebra::Vector3, color::Color, numeric_range::RangeExt, reflect::prelude::*,
26        visitor::prelude::*,
27    },
28    scene::particle_system::{Particle, ParticleSystemRng},
29};
30use std::ops::Range;
31
32/// See module docs.
33#[derive(Debug, Visit, PartialEq, Reflect)]
34pub struct BaseEmitter {
35    /// Offset from center of particle system.
36    position: Vector3<f32>,
37    /// Particle spawn rate in unit-per-second. If < 0, spawns `max_particles`,
38    /// spawns nothing if `max_particles` < 0
39    #[visit(rename = "SpawnRate")]
40    particle_spawn_rate: u32,
41    /// Maximum amount of particles emitter can emit. Unlimited if < 0
42    #[visit(optional)] // Backward compatibility
43    max_particles: Option<u32>,
44    /// Range of initial lifetime of a particle
45    #[visit(rename = "LifeTime")]
46    lifetime: Range<f32>,
47    /// Range of initial size of a particle
48    size: Range<f32>,
49    /// Range of initial size modifier of a particle
50    size_modifier: Range<f32>,
51    /// Range of initial X-component of velocity for a particle
52    x_velocity: Range<f32>,
53    /// Range of initial Y-component of velocity for a particle
54    y_velocity: Range<f32>,
55    /// Range of initial Z-component of velocity for a particle
56    z_velocity: Range<f32>,
57    /// Range of initial rotation speed for a particle
58    rotation_speed: Range<f32>,
59    /// Range of initial rotation for a particle
60    rotation: Range<f32>,
61    #[reflect(hidden)]
62    pub(crate) alive_particles: u32,
63    #[visit(skip)]
64    #[reflect(hidden)]
65    time: f32,
66    #[visit(skip)]
67    #[reflect(hidden)]
68    pub(crate) particles_to_spawn: u32,
69    resurrect_particles: bool,
70    #[reflect(hidden)]
71    pub(crate) spawned_particles: u64,
72}
73
74/// Emitter builder allows you to construct emitter in declarative manner.
75/// This is typical implementation of Builder pattern.
76pub struct BaseEmitterBuilder {
77    position: Option<Vector3<f32>>,
78    particle_spawn_rate: Option<u32>,
79    max_particles: Option<u32>,
80    lifetime: Range<f32>,
81    size: Range<f32>,
82    size_modifier: Range<f32>,
83    x_velocity: Range<f32>,
84    y_velocity: Range<f32>,
85    z_velocity: Range<f32>,
86    rotation_speed: Range<f32>,
87    rotation: Range<f32>,
88    resurrect_particles: bool,
89}
90
91impl Default for BaseEmitterBuilder {
92    fn default() -> Self {
93        Self::new()
94    }
95}
96
97impl BaseEmitterBuilder {
98    /// Creates new emitter builder in declarative manner.
99    pub fn new() -> Self {
100        Self {
101            position: None,
102            particle_spawn_rate: None,
103            max_particles: None,
104            lifetime: 5.0..10.0,
105            size: 0.125..0.250,
106            size_modifier: 0.0005..0.0010,
107            x_velocity: -0.001..0.001,
108            y_velocity: -0.001..0.001,
109            z_velocity: -0.001..0.001,
110            rotation_speed: -0.02..0.02,
111            rotation: -std::f32::consts::PI..std::f32::consts::PI,
112            resurrect_particles: true,
113        }
114    }
115
116    /// Sets desired position of emitter in local coordinates.
117    pub fn with_position(mut self, position: Vector3<f32>) -> Self {
118        self.position = Some(position);
119        self
120    }
121
122    /// Sets desired particle spawn rate in s⁻¹ (particles per second)
123    pub fn with_spawn_rate(mut self, rate: u32) -> Self {
124        self.particle_spawn_rate = Some(rate);
125        self
126    }
127
128    /// Sets desired max amount of particles.
129    pub fn with_max_particles(mut self, value: u32) -> Self {
130        self.max_particles = Some(value);
131        self
132    }
133
134    /// Sets desired lifetime range.
135    pub fn with_lifetime_range(mut self, time_range: Range<f32>) -> Self {
136        self.lifetime = time_range;
137        self
138    }
139
140    /// Sets desired size range.
141    pub fn with_size_range(mut self, size_range: Range<f32>) -> Self {
142        self.size = size_range;
143        self
144    }
145
146    /// Sets desired size modifier range.
147    pub fn with_size_modifier_range(mut self, mod_range: Range<f32>) -> Self {
148        self.size_modifier = mod_range;
149        self
150    }
151
152    /// Sets desired x velocity range.
153    pub fn with_x_velocity_range(mut self, x_vel_range: Range<f32>) -> Self {
154        self.x_velocity = x_vel_range;
155        self
156    }
157
158    /// Sets desired y velocity range.
159    pub fn with_y_velocity_range(mut self, y_vel_range: Range<f32>) -> Self {
160        self.y_velocity = y_vel_range;
161        self
162    }
163
164    /// Sets desired z velocity range.
165    pub fn with_z_velocity_range(mut self, z_vel_range: Range<f32>) -> Self {
166        self.z_velocity = z_vel_range;
167        self
168    }
169
170    /// Sets desired rotation speed range.
171    pub fn with_rotation_speed_range(mut self, speed_range: Range<f32>) -> Self {
172        self.rotation_speed = speed_range;
173        self
174    }
175
176    /// Sets desired rotation range.
177    pub fn with_rotation_range(mut self, angle_range: Range<f32>) -> Self {
178        self.rotation = angle_range;
179        self
180    }
181
182    /// Sets whether to resurrect dead particle or not.
183    pub fn resurrect_particles(mut self, value: bool) -> Self {
184        self.resurrect_particles = value;
185        self
186    }
187
188    /// Creates new instance of emitter.
189    pub fn build(self) -> BaseEmitter {
190        BaseEmitter {
191            position: self.position.unwrap_or_default(),
192            particle_spawn_rate: self.particle_spawn_rate.unwrap_or(25),
193            max_particles: self.max_particles,
194            lifetime: self.lifetime,
195            size: self.size,
196            size_modifier: self.size_modifier,
197            x_velocity: self.x_velocity,
198            y_velocity: self.y_velocity,
199            z_velocity: self.z_velocity,
200            rotation_speed: self.rotation_speed,
201            rotation: self.rotation,
202            alive_particles: 0,
203            time: 0.0,
204            particles_to_spawn: 0,
205            resurrect_particles: self.resurrect_particles,
206            spawned_particles: 0,
207        }
208    }
209}
210
211impl BaseEmitter {
212    /// Updates emitter and emits required amount of particles each call. There is no
213    /// need to call it manually, it will be automatically called by scene update call.
214    pub fn tick(&mut self, dt: f32) {
215        self.time += dt;
216        let time_amount_per_particle = 1.0 / self.particle_spawn_rate as f32;
217        self.particles_to_spawn = (self.time / time_amount_per_particle) as u32;
218        self.time -= time_amount_per_particle * self.particles_to_spawn as f32;
219        if let Some(max_particles) = self.max_particles {
220            let alive_particles = self.alive_particles;
221            if alive_particles < max_particles
222                && alive_particles + self.particles_to_spawn > max_particles
223            {
224                self.particles_to_spawn = max_particles.saturating_sub(alive_particles);
225            }
226            if !self.resurrect_particles && self.spawned_particles >= u64::from(max_particles) {
227                self.particles_to_spawn = 0;
228            }
229        }
230        self.spawned_particles += self.particles_to_spawn as u64;
231    }
232
233    /// Initializes particle with new state. Every custom emitter must call this method,
234    /// otherwise you will get weird behavior of emitted particles.
235    pub fn emit(&self, particle: &mut Particle, rng: &mut ParticleSystemRng) {
236        particle.lifetime = 0.0;
237        particle.initial_lifetime = self.lifetime.random(rng);
238        particle.color = Color::WHITE;
239        particle.size = self.size.random(rng);
240        particle.size_modifier = self.size_modifier.random(rng);
241        particle.velocity = Vector3::new(
242            self.x_velocity.random(rng),
243            self.y_velocity.random(rng),
244            self.z_velocity.random(rng),
245        );
246        particle.rotation = self.rotation.random(rng);
247        particle.rotation_speed = self.rotation_speed.random(rng);
248    }
249
250    /// Sets new position of emitter in local coordinates.
251    pub fn set_position(&mut self, position: Vector3<f32>) -> &mut Self {
252        self.position = position;
253        self
254    }
255
256    /// Returns position of emitter in local coordinates.
257    pub fn position(&self) -> Vector3<f32> {
258        self.position
259    }
260
261    /// Sets new spawn rate in particle per second.
262    pub fn set_spawn_rate(&mut self, rate: u32) -> &mut Self {
263        self.particle_spawn_rate = rate;
264        self
265    }
266
267    /// Return spawn rate in particles per second.
268    pub fn spawn_rate(&self) -> u32 {
269        self.particle_spawn_rate
270    }
271
272    /// Sets maximum amount of particles.
273    pub fn set_max_particles(&mut self, max: Option<u32>) -> &mut Self {
274        self.max_particles = max;
275        self
276    }
277
278    /// Returns maximum amount of particles.
279    pub fn max_particles(&self) -> Option<u32> {
280        self.max_particles
281    }
282
283    /// Sets new range of lifetimes which will be used to generate random lifetime
284    /// of new particle.
285    pub fn set_life_time_range(&mut self, range: Range<f32>) -> &mut Self {
286        self.lifetime = range;
287        self
288    }
289
290    /// Returns current lifetime range.
291    pub fn life_time_range(&self) -> Range<f32> {
292        self.lifetime.clone()
293    }
294
295    /// Sets new range of sizes which will be used to generate random size
296    /// of new particle.
297    pub fn set_size_range(&mut self, range: Range<f32>) -> &mut Self {
298        self.size = range;
299        self
300    }
301
302    /// Returns current size range.
303    pub fn size_range(&self) -> Range<f32> {
304        self.size.clone()
305    }
306
307    /// Sets new range of size modifier which will be used to generate random size modifier
308    /// of new particle.
309    pub fn set_size_modifier_range(&mut self, range: Range<f32>) -> &mut Self {
310        self.size_modifier = range;
311        self
312    }
313
314    /// Returns current size modifier.
315    pub fn size_modifier_range(&self) -> Range<f32> {
316        self.size_modifier.clone()
317    }
318
319    /// Sets new range of initial x velocity that will be used to generate random
320    /// value of initial x velocity of a particle.
321    pub fn set_x_velocity_range(&mut self, range: Range<f32>) -> &mut Self {
322        self.x_velocity = range;
323        self
324    }
325
326    /// Returns current range of initial x velocity that will be used to generate
327    /// random value of initial x velocity of a particle.
328    pub fn x_velocity_range(&self) -> Range<f32> {
329        self.x_velocity.clone()
330    }
331
332    /// Sets new range of initial y velocity that will be used to generate random
333    /// value of initial y velocity of a particle.
334    pub fn set_y_velocity_range(&mut self, range: Range<f32>) -> &mut Self {
335        self.y_velocity = range;
336        self
337    }
338
339    /// Returns current range of initial y velocity that will be used to generate
340    /// random value of initial y velocity of a particle.
341    pub fn y_velocity_range(&self) -> Range<f32> {
342        self.y_velocity.clone()
343    }
344
345    /// Sets new range of initial z velocity that will be used to generate random
346    /// value of initial z velocity of a particle.
347    pub fn set_z_velocity_range(&mut self, range: Range<f32>) -> &mut Self {
348        self.z_velocity = range;
349        self
350    }
351
352    /// Returns current range of initial z velocity that will be used to generate
353    /// random value of initial z velocity of a particle.
354    pub fn z_velocity_range(&self) -> Range<f32> {
355        self.z_velocity.clone()
356    }
357
358    /// Sets new range of rotation speed that will be used to generate random value
359    /// of rotation speed of a particle.
360    pub fn set_rotation_speed_range(&mut self, range: Range<f32>) -> &mut Self {
361        self.rotation_speed = range;
362        self
363    }
364
365    /// Returns current range of rotation speed that will be used to generate random
366    /// value of rotation speed of a particle.
367    pub fn rotation_speed_range(&self) -> Range<f32> {
368        self.rotation_speed.clone()
369    }
370
371    /// Sets new range of initial rotations that will be used to generate random
372    /// value of initial rotation of a particle.
373    pub fn set_rotation_range(&mut self, range: Range<f32>) -> &mut Self {
374        self.rotation = range;
375        self
376    }
377
378    /// Returns current range of initial rotations that will be used to generate
379    /// random value of initial rotation of a particle.
380    pub fn rotation_range(&self) -> Range<f32> {
381        self.rotation.clone()
382    }
383
384    /// Enables or disables automatic particle resurrection. Setting this option to
385    /// true is useful for "endless" effects.
386    pub fn enable_particle_resurrection(&mut self, state: bool) -> &mut Self {
387        self.resurrect_particles = state;
388        self
389    }
390
391    /// Returns true if dead particles will be automatically resurrected, false - otherwise.
392    pub fn is_particles_resurrects(&self) -> bool {
393        self.resurrect_particles
394    }
395
396    /// Returns amount of spawned particles from moment of creation of particle system.
397    pub fn spawned_particles(&self) -> u64 {
398        self.spawned_particles
399    }
400}
401
402impl Clone for BaseEmitter {
403    fn clone(&self) -> Self {
404        Self {
405            position: self.position,
406            particle_spawn_rate: self.particle_spawn_rate,
407            max_particles: self.max_particles,
408            lifetime: self.lifetime.clone(),
409            size: self.size.clone(),
410            size_modifier: self.size_modifier.clone(),
411            x_velocity: self.x_velocity.clone(),
412            y_velocity: self.y_velocity.clone(),
413            z_velocity: self.z_velocity.clone(),
414            rotation_speed: self.rotation_speed.clone(),
415            rotation: self.rotation.clone(),
416            alive_particles: self.alive_particles,
417            time: self.time,
418            particles_to_spawn: 0,
419            resurrect_particles: self.resurrect_particles,
420            spawned_particles: self.spawned_particles,
421        }
422    }
423}
424
425impl Default for BaseEmitter {
426    fn default() -> Self {
427        Self {
428            position: Vector3::default(),
429            particle_spawn_rate: 100,
430            max_particles: None,
431            lifetime: 5.0..10.0,
432            size: 0.125..0.250,
433            size_modifier: 0.0005..0.0010,
434            x_velocity: -0.001..0.001,
435            y_velocity: -0.001..0.001,
436            z_velocity: -0.001..0.001,
437            rotation_speed: -0.02..0.02,
438            rotation: -std::f32::consts::PI..std::f32::consts::PI,
439            alive_particles: 0,
440            time: 0.0,
441            particles_to_spawn: 0,
442            resurrect_particles: true,
443            spawned_particles: 0,
444        }
445    }
446}