fyrox_impl/scene/particle_system/emitter/
sphere.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//! Sphere emitter uniformly places particles in spherical volume. Can be used with
22//! radius = 0, then it represents point emitter.
23
24use crate::{
25    core::{algebra::Vector3, numeric_range::RangeExt, reflect::prelude::*, visitor::prelude::*},
26    scene::particle_system::{
27        emitter::{
28            base::{BaseEmitter, BaseEmitterBuilder},
29            Emit, Emitter,
30        },
31        particle::Particle,
32        ParticleSystemRng,
33    },
34};
35use std::ops::{Deref, DerefMut};
36
37/// See module docs.
38#[derive(Debug, Clone, Reflect, PartialEq, Visit)]
39pub struct SphereEmitter {
40    emitter: BaseEmitter,
41    #[reflect(min_value = 0.0, step = 0.1)]
42    radius: f32,
43}
44
45impl Deref for SphereEmitter {
46    type Target = BaseEmitter;
47
48    fn deref(&self) -> &Self::Target {
49        &self.emitter
50    }
51}
52
53impl DerefMut for SphereEmitter {
54    fn deref_mut(&mut self) -> &mut Self::Target {
55        &mut self.emitter
56    }
57}
58
59impl Default for SphereEmitter {
60    fn default() -> Self {
61        Self {
62            emitter: BaseEmitter::default(),
63            radius: 0.5,
64        }
65    }
66}
67
68impl SphereEmitter {
69    /// Creates new sphere emitter with given radius.
70    pub fn new(emitter: BaseEmitter, radius: f32) -> Self {
71        Self { emitter, radius }
72    }
73
74    /// Returns current radius.
75    pub fn radius(&self) -> f32 {
76        self.radius
77    }
78
79    /// Sets new sphere radius.
80    pub fn set_radius(&mut self, radius: f32) {
81        self.radius = radius.max(0.0);
82    }
83}
84
85impl Emit for SphereEmitter {
86    fn emit(&self, particle: &mut Particle, rng: &mut ParticleSystemRng) {
87        self.emitter.emit(particle, rng);
88        let phi = (0.0..std::f32::consts::PI).random(rng);
89        let theta = (0.0..2.0 * std::f32::consts::PI).random(rng);
90        let radius = (0.0..self.radius).random(rng);
91        let cos_theta = theta.cos();
92        let sin_theta = theta.sin();
93        let cos_phi = phi.cos();
94        let sin_phi = phi.sin();
95        particle.position = self.position()
96            + Vector3::new(
97                radius * sin_theta * cos_phi,
98                radius * sin_theta * sin_phi,
99                radius * cos_theta,
100            );
101    }
102}
103
104/// Sphere emitter builder allows you to construct sphere emitter in declarative manner.
105/// This is typical implementation of Builder pattern.
106pub struct SphereEmitterBuilder {
107    base: BaseEmitterBuilder,
108    radius: f32,
109}
110
111impl SphereEmitterBuilder {
112    /// Creates new sphere emitter builder with 0.5 radius.
113    pub fn new(base: BaseEmitterBuilder) -> Self {
114        Self { base, radius: 0.5 }
115    }
116
117    /// Sets desired radius of sphere emitter.
118    pub fn with_radius(mut self, radius: f32) -> Self {
119        self.radius = radius;
120        self
121    }
122
123    /// Creates new sphere emitter.
124    pub fn build(self) -> Emitter {
125        Emitter::Sphere(SphereEmitter {
126            emitter: self.base.build(),
127            radius: self.radius,
128        })
129    }
130}