Skip to main content

motion_content/particles/
events.rs

1//! Stable event policies and sub-emitter inheritance, independent of rendering.
2
3use super::*;
4
5pub use crate::{Inherit, ParticleEventKind};
6
7/// Event payload ordered by stable nonrecycled particle ID.
8#[derive(Clone, Copy, Debug, PartialEq)]
9pub struct ParticleEvent {
10    /// Exact simulation boundary time (including prewarm offset).
11    pub time: Time,
12    /// Particle state at the event.
13    pub particle: Particle,
14    /// Trigger kind.
15    pub kind: ParticleEventKind,
16}
17
18/// Event-triggered emitter. It receives local step zero and Time::ZERO for each trigger.
19#[derive(Clone)]
20pub struct SubEmitter {
21    /// Birth/death/contact/age trigger.
22    pub on: ParticleEventKind,
23    /// Immutable local emitter definition.
24    pub emitter: Arc<dyn ParticleEmitter>,
25    /// Parent property policy.
26    pub inherit: Inherit,
27    /// Probability in 0..=1, keyed by parent/event/rule.
28    pub probability: f32,
29}
30
31impl SubEmitter {
32    pub(super) fn validate(&self) -> Result<(), ValidationError> {
33        if !self.probability.is_finite() || !(0.0..=1.0).contains(&self.probability) {
34            return Err(invalid(
35                "sub_emitter",
36                "Probability must be finite in 0..=1",
37            ));
38        }
39        if let ParticleEventKind::AgeReached(age) = self.on
40            && (!age.is_finite() || age <= 0.0 || age > 3600.0)
41        {
42            return Err(invalid(
43                "sub_emitter",
44                "Age threshold must be finite in (0,3600]",
45            ));
46        }
47        Ok(())
48    }
49}