use serde::{Deserialize, Serialize};
#[repr(C)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[cfg_attr(feature = "physics-gpu-types", derive(bytemuck::Pod, bytemuck::Zeroable))]
pub struct ParticleState {
pub position: [f32; 3],
pub lifetime: f32,
pub velocity: [f32; 3],
pub age: f32,
pub acceleration: [f32; 3],
pub mass: f32,
pub rotation: [f32; 4],
pub angular_velocity: [f32; 3],
pub drag: f32,
pub color: [f32; 4],
pub scale: [f32; 2],
pub temperature: f32,
pub energy: f32,
pub emitter_id: u32,
pub material_id: u32,
pub flags: u32,
pub seed: u32,
pub tag_mask_lo: u32,
pub tag_mask_hi: u32,
pub custom_f32: [f32; 2],
}
impl ParticleState {
pub const FLAG_ALIVE: u32 = 1 << 0;
pub const FLAG_PROMOTE_CANDIDATE: u32 = 1 << 1;
pub const FLAG_RESTING: u32 = 1 << 2;
pub const FLAG_COLLIDED: u32 = 1 << 3;
pub const FLAG_SIGNAL_CARRIER: u32 = 1 << 4;
pub fn is_alive(&self) -> bool {
self.flags & Self::FLAG_ALIVE != 0
}
pub fn is_promotion_candidate(&self) -> bool {
self.flags & Self::FLAG_PROMOTE_CANDIDATE != 0
}
}
impl Default for ParticleState {
fn default() -> Self {
Self {
position: [0.0; 3],
lifetime: 5.0,
velocity: [0.0; 3],
age: 0.0,
acceleration: [0.0; 3],
mass: 1.0,
rotation: [0.0, 0.0, 0.0, 1.0],
angular_velocity: [0.0; 3],
drag: 0.0,
color: [1.0; 4],
scale: [0.1, 0.1],
temperature: 0.0,
energy: 0.0,
emitter_id: 0,
material_id: 0,
flags: Self::FLAG_ALIVE,
seed: 0,
tag_mask_lo: 0,
tag_mask_hi: 0,
custom_f32: [0.0; 2],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn particle_state_size() {
assert_eq!(std::mem::size_of::<ParticleState>(), 144);
}
#[test]
fn particle_state_default() {
let p = ParticleState::default();
assert!(p.is_alive());
assert!(!p.is_promotion_candidate());
}
#[test]
fn particle_state_flags() {
let mut p = ParticleState::default();
p.flags |= ParticleState::FLAG_PROMOTE_CANDIDATE;
assert!(p.is_promotion_candidate());
p.flags &= !ParticleState::FLAG_ALIVE;
assert!(!p.is_alive());
}
#[test]
fn particle_state_alignment() {
assert_eq!(std::mem::align_of::<ParticleState>(), 4);
}
}