use super::*;
use motion_core::{Node, SceneContext, ValidationError};
type CustomStyle =
Arc<dyn Fn(&[Particle], &SceneContext<'_>) -> Result<Node, ValidationError> + Send + Sync>;
#[derive(Clone)]
pub enum ParticleStyle {
Dots {
radius: f64,
},
GlowDots {
radius: f64,
},
Sprites {
image: motion_core::Handle<crate::ImageAsset>,
size: f64,
align_to_velocity: bool,
},
Trails {
length: Duration,
width: f64,
},
Plexus {
radius: f64,
max_distance: f64,
},
Shape {
radius: f64,
shape: ParticleShape,
},
Bokeh {
radius: f64,
aperture: f32,
focus: f32,
shape: BokehShape,
ring: f32,
hardness: f32,
highlight: f32,
},
Configured {
style: Box<ParticleStyle>,
options: StyleOptions,
},
Custom(CustomStyle),
}
pub type ParticleBlend = motion_core::instances::InstanceBlend;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ParticleShape {
Polygon {
sides: u8,
},
Ring {
thickness: f32,
},
Capsule {
aspect: f32,
},
Soft {
hardness: f32,
},
Quad {
aspect: f32,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BokehShape {
Disc,
Polygon(u8),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SpeedStretch {
pub scale: f32,
pub maximum: f32,
}
#[derive(Clone)]
pub struct TrailOptions {
pub segments: u8,
pub taper: Option<ParticleCurve>,
pub fade: Option<ParticleCurve>,
pub smooth: bool,
pub ribbon: bool,
}
impl Default for TrailOptions {
fn default() -> Self {
Self {
segments: 8,
taper: None,
fade: None,
smooth: false,
ribbon: false,
}
}
}
#[derive(Clone, Default)]
pub struct StyleOptions {
pub blend: Option<ParticleBlend>,
pub sheet: Option<SpriteSheet>,
pub trails: TrailOptions,
pub stretch: Option<SpeedStretch>,
pub parallax: [f32; 2],
pub sort_depth: bool,
pub flip: bool,
}
impl ParticleStyle {
fn configure(self, update: impl FnOnce(&mut StyleOptions)) -> Self {
let (style, mut options) = match self {
Self::Configured { style, options } => (style, options),
style => (Box::new(style), StyleOptions::default()),
};
update(&mut options);
Self::Configured { style, options }
}
pub fn blend(self, blend: ParticleBlend) -> Self {
self.configure(|options| options.blend = Some(blend))
}
pub fn sheet(self, sheet: SpriteSheet) -> Self {
self.configure(|options| options.sheet = Some(sheet))
}
pub fn trails(self, trails: TrailOptions) -> Self {
self.configure(|options| options.trails = trails)
}
pub fn stretch_by_speed(self, scale: f32, maximum: f32) -> Self {
self.configure(|options| options.stretch = Some(SpeedStretch { scale, maximum }))
}
pub fn parallax(self, offset: [f32; 2]) -> Self {
self.configure(|options| {
options.parallax = offset;
options.sort_depth = true;
})
}
pub fn flip(self) -> Self {
self.configure(|options| options.flip = true)
}
}
impl Default for ParticleStyle {
fn default() -> Self {
Self::Dots { radius: 2.0 }
}
}