fyrox_impl/scene/particle_system/emitter/
cylinder.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//! Vertical cylinder emitter.
22
23use crate::{
24    core::{algebra::Vector3, numeric_range::RangeExt, reflect::prelude::*, visitor::prelude::*},
25    scene::particle_system::{
26        emitter::{
27            base::{BaseEmitter, BaseEmitterBuilder},
28            Emit, Emitter,
29        },
30        particle::Particle,
31        ParticleSystemRng,
32    },
33};
34use std::ops::{Deref, DerefMut};
35
36/// See module docs.
37#[derive(Clone, Debug, Visit, PartialEq, Reflect)]
38pub struct CylinderEmitter {
39    emitter: BaseEmitter,
40    #[reflect(min_value = 0.0, step = 0.1)]
41    height: f32,
42    #[reflect(min_value = 0.0, step = 0.1)]
43    radius: f32,
44}
45
46impl Default for CylinderEmitter {
47    fn default() -> Self {
48        Self {
49            emitter: Default::default(),
50            height: 1.0,
51            radius: 0.5,
52        }
53    }
54}
55
56impl Deref for CylinderEmitter {
57    type Target = BaseEmitter;
58
59    fn deref(&self) -> &Self::Target {
60        &self.emitter
61    }
62}
63
64impl DerefMut for CylinderEmitter {
65    fn deref_mut(&mut self) -> &mut Self::Target {
66        &mut self.emitter
67    }
68}
69
70impl Emit for CylinderEmitter {
71    fn emit(&self, particle: &mut Particle, rng: &mut ParticleSystemRng) {
72        // Disk point picking extended in 3D - http://mathworld.wolfram.com/DiskPointPicking.html
73        let scale: f32 = (0.0..1.0).random(rng);
74        let theta = (0.0..2.0 * std::f32::consts::PI).random(rng);
75        let z = (0.0..self.height).random(rng);
76        let radius = scale.sqrt() * self.radius;
77        let x = radius * theta.cos();
78        let y = radius * theta.sin();
79        particle.position = self.position() + Vector3::new(x, y, z);
80    }
81}
82
83impl CylinderEmitter {
84    /// Returns radius of the cylinder emitter.
85    pub fn radius(&self) -> f32 {
86        self.radius
87    }
88
89    /// Sets radius of the cylinder emitter.
90    pub fn set_radius(&mut self, radius: f32) {
91        self.radius = radius.max(0.0);
92    }
93
94    /// Returns height of the cylinder emitter.
95    pub fn height(&self) -> f32 {
96        self.height
97    }
98
99    /// Sets height of the cylinder emitter.
100    pub fn set_height(&mut self, height: f32) {
101        self.height = height.max(0.0);
102    }
103}
104
105/// Box emitter builder allows you to construct cylinder emitter in declarative manner.
106/// This is typical implementation of Builder pattern.
107pub struct CylinderEmitterBuilder {
108    base: BaseEmitterBuilder,
109    height: f32,
110    radius: f32,
111}
112
113impl CylinderEmitterBuilder {
114    /// Creates new cylinder emitter builder.
115    pub fn new(base: BaseEmitterBuilder) -> Self {
116        Self {
117            base,
118            height: 1.0,
119            radius: 0.5,
120        }
121    }
122
123    /// Sets desired height of the emitter.
124    pub fn with_height(mut self, height: f32) -> Self {
125        self.height = height;
126        self
127    }
128
129    /// Sets desired radius of the emitter.
130    pub fn with_radius(mut self, radius: f32) -> Self {
131        self.radius = radius;
132        self
133    }
134
135    /// Creates new cylinder emitter with given parameters.
136    pub fn build(self) -> Emitter {
137        Emitter::Cylinder(CylinderEmitter {
138            emitter: self.base.build(),
139            height: self.height,
140            radius: self.radius,
141        })
142    }
143}