1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::strip::EffectIterator;
use palette::{FromColor, Hsv, MixAssign, Srgb};
use rand::{thread_rng, Rng};

use crate::utils::srgbu8_to_hsv;

pub struct Sparkle {
    colour: Srgb,
    intensity: f32,
    location: usize,
}

pub struct Christmas {
    frequency: u8,
    probability: f32,
    fade: f32,
    sparkles: Vec<Sparkle>,
    length: usize,
}

impl Christmas {
    const DEFAULT_FREQUENCY: u8 = 0x04;
    const DEFAULT_PROBABILITY: f32 = 0.1;
    const DEFAULT_FADE: f32 = 0.4;
    const BASE_BRIGHTNESS: f32 = 1.0;
    const BACKGROUND: Srgb = Srgb::new(6.0 / 255.0, 108.0 / 255.0, 22.0 / 255.0);

    pub fn new(
        count: usize,
        colour: Option<Srgb<u8>>,
        sparkle: Option<u8>,
        probability: Option<f32>,
        fade: Option<f32>,
    ) -> Self {
        let mut colour = match colour {
            Some(colour) => srgbu8_to_hsv(colour),
            None => Hsv::from_color(Self::BACKGROUND),
        };

        colour.value = Christmas::BASE_BRIGHTNESS;

        Christmas {
            frequency: sparkle.unwrap_or(Christmas::DEFAULT_FREQUENCY),
            fade: fade.unwrap_or(Christmas::DEFAULT_FADE),
            probability: probability.unwrap_or(Christmas::DEFAULT_PROBABILITY),
            sparkles: Vec::new(),
            length: count,
        }
    }
}

impl Christmas {
    fn generate_sparkle(&mut self) {
        let mut rng = thread_rng();

        let chance = rng.gen_range(0.0..1.0);
        if chance > self.probability {
            return;
        }

        let index = rng.gen_range(0..self.length);

        let c_index = rng.gen_range(0.0..1.0);

        let colour = if c_index < 0.5 {
            Srgb::new(1.0, 0.0, 0.0)
        } else if c_index < 0.80 {
            Srgb::new(0.0, 0.84, 1.0)
        } else {
            Srgb::new(0.0, 0.0, 1.0)
        };

        self.sparkles.push(Sparkle {
            colour,
            intensity: 1.0,
            location: index,
        });
    }

    fn fade_sparkles(&mut self) {
        for sparkle in self.sparkles.iter_mut() {
            sparkle.intensity -= self.fade;
            sparkle.intensity = sparkle.intensity.max(0.0);
        }
        self.sparkles.retain(|sparkle| sparkle.intensity > 0.0);
    }
}

impl EffectIterator for Christmas {
    fn name(&self) -> &'static str {
        "Christmas"
    }

    fn next(&mut self) -> Option<Vec<Srgb<u8>>> {
        self.fade_sparkles();

        let chances = thread_rng().gen_range(0..self.frequency);
        for _ in 0..chances {
            self.generate_sparkle();
        }

        let mut out: Vec<Srgb> = vec![self::Christmas::BACKGROUND; self.length];

        for sparkle in self.sparkles.iter() {
            out[sparkle.location].mix_assign(sparkle.colour, sparkle.intensity);
        }

        Some(out.iter().map(|&c| c.into_format::<u8>()).collect())
    }
}