use nalgebra_glm::{Vec3, Vec4};
use serde::{Deserialize, Serialize};
use crate::ecs::particles::components::{
ColorGradient, EmitterShape, EmitterType, ParticleEmitter,
};
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
pub enum SceneEmitterType {
Firework,
#[default]
Fire,
Smoke,
Sparks,
Trail,
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Default)]
pub enum SceneEmitterShape {
#[default]
Point,
Sphere {
radius: f32,
},
Cone {
angle: f32,
height: f32,
},
Box {
half_extents: [f32; 3],
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneColorGradient {
pub colors: Vec<(f32, [f32; 4])>,
}
impl Default for SceneColorGradient {
fn default() -> Self {
Self {
colors: vec![(0.0, [1.0, 1.0, 1.0, 1.0]), (1.0, [1.0, 1.0, 1.0, 0.0])],
}
}
}
impl From<&ColorGradient> for SceneColorGradient {
fn from(gradient: &ColorGradient) -> Self {
Self {
colors: gradient
.colors
.iter()
.map(|(time, color)| (*time, [color.x, color.y, color.z, color.w]))
.collect(),
}
}
}
impl SceneColorGradient {
pub fn to_color_gradient(&self) -> ColorGradient {
ColorGradient {
colors: self
.colors
.iter()
.map(|(time, color)| (*time, Vec4::new(color[0], color[1], color[2], color[3])))
.collect(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct SceneParticleEmitter {
pub emitter_type: SceneEmitterType,
pub shape: SceneEmitterShape,
pub position: [f32; 3],
pub direction: [f32; 3],
pub spawn_rate: f32,
pub burst_count: u32,
pub particle_lifetime_min: f32,
pub particle_lifetime_max: f32,
pub initial_velocity_min: f32,
pub initial_velocity_max: f32,
pub velocity_spread: f32,
pub gravity: [f32; 3],
pub drag: f32,
pub size_start: f32,
pub size_end: f32,
pub color_gradient: SceneColorGradient,
pub emissive_strength: f32,
pub enabled: bool,
pub one_shot: bool,
pub turbulence_strength: f32,
pub turbulence_frequency: f32,
pub texture_index: u32,
}
impl Default for SceneParticleEmitter {
fn default() -> Self {
Self {
emitter_type: SceneEmitterType::Fire,
shape: SceneEmitterShape::Point,
position: [0.0, 0.0, 0.0],
direction: [0.0, 1.0, 0.0],
spawn_rate: 100.0,
burst_count: 0,
particle_lifetime_min: 1.0,
particle_lifetime_max: 2.0,
initial_velocity_min: 1.0,
initial_velocity_max: 3.0,
velocity_spread: 0.3,
gravity: [0.0, -9.81, 0.0],
drag: 0.1,
size_start: 0.1,
size_end: 0.0,
color_gradient: SceneColorGradient::default(),
emissive_strength: 1.0,
enabled: true,
one_shot: false,
turbulence_strength: 0.0,
turbulence_frequency: 1.0,
texture_index: 0,
}
}
}
impl From<&ParticleEmitter> for SceneParticleEmitter {
fn from(emitter: &ParticleEmitter) -> Self {
Self {
emitter_type: match emitter.emitter_type {
EmitterType::Firework => SceneEmitterType::Firework,
EmitterType::Fire => SceneEmitterType::Fire,
EmitterType::Smoke => SceneEmitterType::Smoke,
EmitterType::Sparks => SceneEmitterType::Sparks,
EmitterType::Trail => SceneEmitterType::Trail,
},
shape: match emitter.shape {
EmitterShape::Point => SceneEmitterShape::Point,
EmitterShape::Sphere { radius } => SceneEmitterShape::Sphere { radius },
EmitterShape::Cone { angle, height } => SceneEmitterShape::Cone { angle, height },
EmitterShape::Box { half_extents } => SceneEmitterShape::Box {
half_extents: [half_extents.x, half_extents.y, half_extents.z],
},
},
position: [emitter.position.x, emitter.position.y, emitter.position.z],
direction: [
emitter.direction.x,
emitter.direction.y,
emitter.direction.z,
],
spawn_rate: emitter.spawn_rate,
burst_count: emitter.burst_count,
particle_lifetime_min: emitter.particle_lifetime_min,
particle_lifetime_max: emitter.particle_lifetime_max,
initial_velocity_min: emitter.initial_velocity_min,
initial_velocity_max: emitter.initial_velocity_max,
velocity_spread: emitter.velocity_spread,
gravity: [emitter.gravity.x, emitter.gravity.y, emitter.gravity.z],
drag: emitter.drag,
size_start: emitter.size_start,
size_end: emitter.size_end,
color_gradient: SceneColorGradient::from(&emitter.color_gradient),
emissive_strength: emitter.emissive_strength,
enabled: emitter.enabled,
one_shot: emitter.one_shot,
turbulence_strength: emitter.turbulence_strength,
turbulence_frequency: emitter.turbulence_frequency,
texture_index: emitter.texture_index,
}
}
}
impl SceneParticleEmitter {
pub fn to_particle_emitter(&self) -> ParticleEmitter {
ParticleEmitter {
emitter_type: match self.emitter_type {
SceneEmitterType::Firework => EmitterType::Firework,
SceneEmitterType::Fire => EmitterType::Fire,
SceneEmitterType::Smoke => EmitterType::Smoke,
SceneEmitterType::Sparks => EmitterType::Sparks,
SceneEmitterType::Trail => EmitterType::Trail,
},
shape: match self.shape {
SceneEmitterShape::Point => EmitterShape::Point,
SceneEmitterShape::Sphere { radius } => EmitterShape::Sphere { radius },
SceneEmitterShape::Cone { angle, height } => EmitterShape::Cone { angle, height },
SceneEmitterShape::Box { half_extents } => EmitterShape::Box {
half_extents: Vec3::new(half_extents[0], half_extents[1], half_extents[2]),
},
},
position: Vec3::new(self.position[0], self.position[1], self.position[2]),
direction: Vec3::new(self.direction[0], self.direction[1], self.direction[2]),
spawn_rate: self.spawn_rate,
burst_count: self.burst_count,
particle_lifetime_min: self.particle_lifetime_min,
particle_lifetime_max: self.particle_lifetime_max,
initial_velocity_min: self.initial_velocity_min,
initial_velocity_max: self.initial_velocity_max,
velocity_spread: self.velocity_spread,
gravity: Vec3::new(self.gravity[0], self.gravity[1], self.gravity[2]),
drag: self.drag,
size_start: self.size_start,
size_end: self.size_end,
color_gradient: self.color_gradient.to_color_gradient(),
emissive_strength: self.emissive_strength,
enabled: self.enabled,
accumulated_spawn: 0.0,
one_shot: self.one_shot,
has_fired: false,
turbulence_strength: self.turbulence_strength,
turbulence_frequency: self.turbulence_frequency,
texture_index: self.texture_index,
}
}
}