firework_rs/
demo.rs

1//! This module provides some demos of different types of fireworks
2
3use std::{
4    f32::consts::PI,
5    time::{Duration, SystemTime},
6};
7
8use glam::Vec2;
9use rand::{seq::IteratorRandom, thread_rng, Rng};
10
11use crate::{
12    config::Config,
13    fireworks::{ExplosionForm, Firework, FireworkConfig},
14    particle::ParticleConfig,
15    utils::{
16        explosion_gradient_1, explosion_gradient_2, explosion_gradient_3, gen_points_arc,
17        gen_points_circle, gen_points_circle_normal, gen_points_circle_normal_dev, gen_points_fan,
18        linear_gradient_1,
19    },
20};
21
22pub fn demo_firework_0(
23    center: Vec2,
24    spawn_after: Duration,
25    enable_gradient: bool,
26    colors: Vec<(u8, u8, u8)>,
27    cfg: &Config,
28) -> Firework {
29    let mut particles = Vec::new();
30    for v in gen_points_circle_normal(
31        thread_rng().gen_range(if cfg.enable_cjk {
32            400.0..600.0
33        } else {
34            230.0..400.0
35        }),
36        thread_rng().gen_range(if cfg.enable_cjk { 20..35 } else { 33..47 }),
37    )
38    .iter()
39    {
40        particles.push(ParticleConfig::new(
41            center,
42            *v,
43            thread_rng().gen_range(20..25),
44            Duration::from_secs_f32(thread_rng().gen_range(1.8..2.3)),
45            *colors.iter().choose(&mut thread_rng()).unwrap(),
46        ));
47    }
48    let mut config = FireworkConfig::default().with_gradient_scale(explosion_gradient_1);
49    config.set_enable_gradient(enable_gradient);
50    Firework {
51        init_time: SystemTime::now(),
52        spawn_after,
53        center,
54        particles,
55        config,
56        ..Default::default()
57    }
58}
59
60pub fn demo_firework_1(center: Vec2, spawn_after: Duration, enable_gradient: bool) -> Firework {
61    let colors = [
62        (255, 102, 75),
63        (144, 56, 67),
64        (255, 225, 124),
65        (206, 32, 41),
66    ];
67    let mut particles = Vec::new();
68    for v in gen_points_circle_normal(250., 45).iter() {
69        particles.push(ParticleConfig::new(
70            center,
71            *v,
72            thread_rng().gen_range(23..27),
73            Duration::from_secs_f32(thread_rng().gen_range(2.1..2.7)),
74            *colors.iter().choose(&mut thread_rng()).unwrap(),
75        ));
76    }
77    let mut config = FireworkConfig::default().with_gradient_scale(explosion_gradient_1);
78    config.set_enable_gradient(enable_gradient);
79    Firework {
80        init_time: SystemTime::now(),
81        spawn_after,
82        center,
83        particles,
84        config,
85        ..Default::default()
86    }
87}
88
89pub fn demo_firework_2(center: Vec2, spawn_after: Duration, enable_gradient: bool) -> Firework {
90    let colors = [(250, 216, 68)];
91    let mut particles = Vec::new();
92    for v in gen_points_circle(100, 600).iter() {
93        particles.push(ParticleConfig::new(
94            center,
95            *v,
96            thread_rng().gen_range(5..8),
97            Duration::from_secs_f32(thread_rng().gen_range(3.0..5.5)),
98            *colors.iter().choose(&mut thread_rng()).unwrap(),
99        ));
100    }
101    let mut config = FireworkConfig::default()
102        .with_gradient_scale(explosion_gradient_2)
103        .with_gravity_scale(0.)
104        .with_ar_scale(0.15);
105    config.set_enable_gradient(enable_gradient);
106    Firework {
107        init_time: SystemTime::now(),
108        spawn_after,
109        center,
110        particles,
111        config,
112        ..Default::default()
113    }
114}
115
116pub fn demo_firework_3(center: Vec2, spawn_after: Duration, enable_gradient: bool) -> Firework {
117    let colors = [
118        (242, 233, 190),
119        (226, 196, 136),
120        (149, 202, 176),
121        (26, 64, 126),
122    ];
123    let mut particles = Vec::new();
124    for v in gen_points_circle_normal(350., 135).iter() {
125        particles.push(ParticleConfig::new(
126            center,
127            *v,
128            thread_rng().gen_range(23..43),
129            Duration::from_secs_f32(thread_rng().gen_range(3.5..5.0)),
130            *colors.iter().choose(&mut thread_rng()).unwrap(),
131        ));
132    }
133    let mut config = FireworkConfig::default()
134        .with_gradient_scale(explosion_gradient_1)
135        .with_ar_scale(0.18)
136        .with_gravity_scale(0.7);
137    config.set_enable_gradient(enable_gradient);
138    Firework {
139        init_time: SystemTime::now(),
140        spawn_after,
141        center,
142        particles,
143        config,
144        ..Default::default()
145    }
146}
147
148pub fn demo_firework_4(center: Vec2, spawn_after: Duration, enable_gradient: bool) -> Firework {
149    let colors = [(242, 233, 190), (226, 196, 136), (255, 248, 253)];
150    let mut particles = Vec::new();
151    for v in gen_points_circle_normal(350., 25).iter() {
152        particles.push(ParticleConfig::new(
153            center,
154            *v,
155            thread_rng().gen_range(20..33),
156            Duration::from_secs_f32(thread_rng().gen_range(3.5..5.0)),
157            *colors.iter().choose(&mut thread_rng()).unwrap(),
158        ));
159    }
160    let mut config = FireworkConfig::default()
161        .with_gradient_scale(explosion_gradient_1)
162        .with_gravity_scale(0.3);
163    config.set_enable_gradient(enable_gradient);
164    Firework {
165        init_time: SystemTime::now(),
166        spawn_after,
167        center,
168        particles,
169        config,
170        ..Default::default()
171    }
172}
173
174pub fn demo_firework_5(center: Vec2, spawn_after: Duration, enable_gradient: bool) -> Firework {
175    let colors = [(152, 186, 227), (54, 84, 117), (21, 39, 60)];
176    let mut particles = Vec::new();
177    for v in gen_points_circle_normal(450., 80).iter() {
178        particles.push(ParticleConfig::new(
179            center,
180            *v,
181            thread_rng().gen_range(33..43),
182            Duration::from_secs_f32(thread_rng().gen_range(3.5..5.0)),
183            *colors.iter().choose(&mut thread_rng()).unwrap(),
184        ));
185    }
186    let mut config = FireworkConfig::default()
187        .with_gradient_scale(explosion_gradient_3)
188        .with_gravity_scale(1.4);
189    config.set_enable_gradient(enable_gradient);
190    Firework {
191        init_time: SystemTime::now(),
192        spawn_after,
193        center,
194        particles,
195        config,
196        ..Default::default()
197    }
198}
199
200pub fn demo_firework_6(center: Vec2, spawn_after: Duration, enable_gradient: bool) -> Firework {
201    let colors = [(242, 233, 190), (226, 196, 136), (255, 248, 253)];
202    let mut particles = Vec::new();
203    for v in gen_points_circle_normal(350., 35).iter() {
204        particles.push(ParticleConfig::new(
205            center,
206            *v,
207            thread_rng().gen_range(20..23),
208            Duration::from_secs_f32(thread_rng().gen_range(3.5..4.0)),
209            *colors.iter().choose(&mut thread_rng()).unwrap(),
210        ));
211    }
212    let mut config = FireworkConfig::default()
213        .with_gradient_scale(explosion_gradient_1)
214        .with_ar_scale(0.19)
215        .with_gravity_scale(0.1);
216    config.set_enable_gradient(enable_gradient);
217    Firework {
218        init_time: SystemTime::now(),
219        spawn_after,
220        center,
221        particles,
222        config,
223        ..Default::default()
224    }
225}
226
227pub fn demo_firework_comb_1(
228    start: Vec2,
229    spawn_after: Duration,
230    enable_gradient: bool,
231) -> Vec<Firework> {
232    // Ascent of rocket
233    let color1 = (255, 255, 235);
234    let particles1 = ParticleConfig::new(
235        start,
236        Vec2::NEG_Y * 160.,
237        6,
238        Duration::from_secs_f32(1.2),
239        color1,
240    );
241    let mut config1 = FireworkConfig::default()
242        .with_ar_scale(0.04)
243        .with_gradient_scale(linear_gradient_1);
244    config1.set_enable_gradient(enable_gradient);
245
246    // Explosion
247    let color2 = [
248        (235, 39, 155),
249        (250, 216, 68),
250        (242, 52, 72),
251        (63, 52, 200),
252        (255, 139, 57),
253    ];
254    let center2 = start + Vec2::NEG_Y * 53.;
255    let mut particles2 = Vec::new();
256    for v in gen_points_circle_normal(350., 160).iter() {
257        particles2.push(ParticleConfig::new(
258            center2,
259            *v,
260            thread_rng().gen_range(23..43),
261            Duration::from_secs_f32(thread_rng().gen_range(2.5..4.5)),
262            *color2.iter().choose(&mut thread_rng()).unwrap(),
263        ));
264    }
265    let mut config2 = FireworkConfig::default()
266        .with_gradient_scale(explosion_gradient_1)
267        .with_ar_scale(0.2)
268        .with_gravity_scale(0.3);
269    config2.set_enable_gradient(enable_gradient);
270    vec![
271        Firework {
272            init_time: SystemTime::now(),
273            spawn_after,
274            center: start,
275            particles: vec![particles1],
276            config: config1,
277            ..Default::default()
278        },
279        Firework {
280            init_time: SystemTime::now(),
281            spawn_after: spawn_after + Duration::from_secs_f32(1.2),
282            center: center2,
283            particles: particles2,
284            config: config2,
285            ..Default::default()
286        },
287    ]
288}
289
290pub fn demo_firework_comb_0(
291    center: Vec2,
292    spawn_after: Duration,
293    enable_gradient: bool,
294) -> Vec<Firework> {
295    vec![
296        demo_firework_3(center + Vec2::new(-5., -19.), spawn_after, enable_gradient),
297        demo_firework_4(
298            center + Vec2::new(-30., 0.),
299            spawn_after + Duration::from_secs_f32(0.4),
300            enable_gradient,
301        ),
302        demo_firework_5(
303            center + Vec2::new(12., 0.),
304            spawn_after + Duration::from_secs_f32(1.6),
305            enable_gradient,
306        ),
307        demo_firework_1(
308            center + Vec2::new(-9., 7.),
309            spawn_after + Duration::from_secs_f32(2.),
310            enable_gradient,
311        ),
312        demo_firework_6(
313            center + Vec2::new(24., -11.),
314            spawn_after + Duration::from_secs_f32(2.3),
315            enable_gradient,
316        ),
317    ]
318}
319
320pub fn demo_firework_comb_2(
321    center: Vec2,
322    spawn_after: Duration,
323    enable_gradient: bool,
324) -> Vec<Firework> {
325    let mut res = Vec::new();
326    let fountain1 = |center: Vec2, angle: f32| {
327        let colors = [(255, 183, 3), (251, 133, 0), (242, 233, 190)];
328        let mut particles = Vec::new();
329        for v in gen_points_fan(60., 20, angle - 0.05, angle + 0.05).iter() {
330            particles.push(ParticleConfig::new(
331                center,
332                *v,
333                thread_rng().gen_range(28..38),
334                Duration::from_secs_f32(thread_rng().gen_range(2.5..3.8)),
335                *colors.iter().choose(&mut thread_rng()).unwrap(),
336            ));
337        }
338        let mut config = FireworkConfig::default()
339            .with_ar_scale(0.05)
340            .with_gradient_scale(linear_gradient_1);
341        config.set_enable_gradient(enable_gradient);
342        Firework {
343            init_time: SystemTime::now(),
344            spawn_after,
345            center,
346            particles,
347            config,
348            form: ExplosionForm::Sustained {
349                lasts: Duration::from_secs(5),
350                time_interval: Duration::from_secs_f32(0.08),
351                timer: Duration::ZERO,
352            },
353            ..Default::default()
354        }
355    };
356
357    let fountain2 = |center: Vec2| {
358        let colors = [(226, 196, 136), (255, 245, 253), (208, 58, 99)];
359        let mut particles = Vec::new();
360        for v in gen_points_fan(1000., 20, 5.7 / 12. * PI, 6.3 / 12. * PI).iter() {
361            particles.push(ParticleConfig::new(
362                center,
363                *v,
364                thread_rng().gen_range(28..38),
365                Duration::from_secs_f32(thread_rng().gen_range(2.5..3.8)),
366                *colors.iter().choose(&mut thread_rng()).unwrap(),
367            ));
368        }
369        let mut config = FireworkConfig::default()
370            .with_ar_scale(0.14)
371            .with_gravity_scale(0.9)
372            .with_gradient_scale(linear_gradient_1);
373        config.set_enable_gradient(enable_gradient);
374        Firework {
375            init_time: SystemTime::now(),
376            spawn_after: spawn_after + Duration::from_secs_f32(4.),
377            center,
378            particles,
379            config,
380            form: ExplosionForm::Sustained {
381                lasts: Duration::from_secs(5),
382                time_interval: Duration::from_secs_f32(0.08),
383                timer: Duration::ZERO,
384            },
385            ..Default::default()
386        }
387    };
388
389    let mono = |center: Vec2, sa: Duration, colors: Vec<(u8, u8, u8)>| {
390        let particles = vec![ParticleConfig::new(
391            center,
392            gen_points_arc(200., 1, 5. / 12. * PI, 7. / 12. * PI)[0],
393            thread_rng().gen_range(24..30),
394            Duration::from_secs_f32(thread_rng().gen_range(2.1..2.7)),
395            *colors.iter().choose(&mut thread_rng()).unwrap(),
396        )];
397        let mut config = FireworkConfig::default()
398            .with_ar_scale(thread_rng().gen_range(0.18..0.24))
399            .with_gradient_scale(linear_gradient_1);
400        config.set_enable_gradient(enable_gradient);
401        Firework {
402            init_time: SystemTime::now(),
403            spawn_after: sa,
404            center,
405            particles,
406            config,
407            form: ExplosionForm::Instant { used: false },
408            ..Default::default()
409        }
410    };
411
412    res.push(fountain1(center + Vec2::new(-31., 21.), 1.05));
413    res.push(fountain1(center + Vec2::new(31., 21.), 2.09));
414
415    res.push(fountain2(center + Vec2::new(-7., 21.)));
416    res.push(fountain2(center + Vec2::new(7., 21.)));
417
418    (-33..=33).step_by(3).for_each(|i| {
419        res.push(mono(
420            Vec2::new(center.x + i as f32, center.y + 21.),
421            Duration::from_secs_f32(3.5),
422            vec![(0, 119, 182), (144, 224, 239), (12, 180, 216)],
423        ))
424    });
425
426    (-33..=33).step_by(3).for_each(|i| {
427        res.push(mono(
428            Vec2::new(center.x + i as f32, center.y + 21.),
429            Duration::from_secs_f32(4.7),
430            vec![(181, 23, 158), (247, 37, 133), (114, 9, 183)],
431        ))
432    });
433
434    (-33..=33).step_by(3).for_each(|i| {
435        res.push(mono(
436            Vec2::new(center.x + i as f32, center.y + 21.),
437            Duration::from_secs_f32(5.9),
438            vec![(217, 237, 146), (153, 217, 140), (82, 182, 154)],
439        ))
440    });
441
442    res
443}
444
445pub fn demo_firework_comb_3(
446    center: Vec2,
447    spawn_after: Duration,
448    enable_gradient: bool,
449) -> Vec<Firework> {
450    let mut res = Vec::new();
451    let f1 = {
452        let colors = [(255, 216, 190), (255, 238, 221), (248, 247, 255)];
453        let mut particles = Vec::new();
454        for v in gen_points_circle_normal_dev(14., 200, 60.).iter() {
455            particles.push(ParticleConfig::new(
456                center + Vec2::NEG_Y * 6.,
457                *v,
458                thread_rng().gen_range(15..20),
459                Duration::from_secs_f32(thread_rng().gen_range(3.0..5.0)),
460                *colors.iter().choose(&mut thread_rng()).unwrap(),
461            ));
462        }
463        let mut config = FireworkConfig::default()
464            .with_gradient_scale(explosion_gradient_1)
465            .with_ar_scale(0.15)
466            .with_gravity_scale(0.35);
467        config.set_enable_gradient(enable_gradient);
468        Firework {
469            init_time: SystemTime::now(),
470            spawn_after,
471            center,
472            particles,
473            config,
474            ..Default::default()
475        }
476    };
477    res.push(f1);
478    let f2 = {
479        let colors = [
480            (152, 186, 227),
481            (89, 129, 177),
482            (54, 84, 117),
483            (240, 244, 254),
484        ];
485        let mut particles = Vec::new();
486        for v in gen_points_circle_normal_dev(10000., 600, 30.).iter() {
487            particles.push(ParticleConfig::new(
488                center + Vec2::NEG_Y * 6.,
489                *v,
490                thread_rng().gen_range(20..28),
491                Duration::from_secs_f32(thread_rng().gen_range(4.8..10.)),
492                *colors.iter().choose(&mut thread_rng()).unwrap(),
493            ));
494        }
495        let mut config = FireworkConfig::default()
496            .with_gradient_scale(explosion_gradient_1)
497            .with_ar_scale(0.09)
498            .with_gravity_scale(0.5);
499        config.set_enable_gradient(enable_gradient);
500        Firework {
501            init_time: SystemTime::now(),
502            spawn_after,
503            center,
504            particles,
505            config,
506            ..Default::default()
507        }
508    };
509    res.push(f2);
510
511    for (idx, p) in gen_points_circle(27, 10).iter().enumerate() {
512        let colors = [(17, 138, 178), (6, 214, 160), (7, 59, 76), (255, 255, 255)];
513        let mut particles = Vec::new();
514        for v in gen_points_circle_normal_dev(100., 35, 350. / 9.).iter() {
515            particles.push(ParticleConfig::new(
516                center + *p,
517                *v,
518                thread_rng().gen_range(20..30),
519                Duration::from_secs_f32(thread_rng().gen_range(3.0..4.0)),
520                *colors.iter().choose(&mut thread_rng()).unwrap(),
521            ));
522        }
523        let mut config = FireworkConfig::default()
524            .with_gradient_scale(explosion_gradient_3)
525            .with_ar_scale(0.28)
526            .with_gravity_scale(0.25);
527        config.set_enable_gradient(enable_gradient);
528        res.push(Firework {
529            init_time: SystemTime::now(),
530            spawn_after: spawn_after + Duration::from_secs_f32(0.2 * (idx + 4) as f32),
531            center,
532            particles,
533            config,
534            ..Default::default()
535        });
536    }
537
538    res
539}