vortex/
vortex.rs

1use std::{
2    io::{stdout, Result},
3    thread::sleep,
4    time::{Duration, SystemTime},
5};
6
7use crossterm::{
8    cursor,
9    event::{self, KeyCode},
10    execute, terminal,
11};
12use firework_rs::{
13    config::Config,
14    fireworks::{ExplosionForm, Firework, FireworkConfig, FireworkManager},
15    particle::ParticleConfig,
16    term::Terminal,
17    utils::gen_points_circle,
18};
19use glam::Vec2;
20use rand::{seq::IteratorRandom, thread_rng, Rng};
21
22fn main() -> Result<()> {
23    let mut stdout = stdout();
24    let (_width, _height) = terminal::size()?;
25    let mut is_running = true;
26    let cfg = Config::default();
27
28    terminal::enable_raw_mode()?;
29    execute!(stdout, terminal::EnterAlternateScreen, cursor::Hide)?;
30
31    let mut time = SystemTime::now();
32    let mut term = Terminal::default();
33    let mut fm = FireworkManager::default().with_firework(gen_vortex_firework(Vec2::new(
34        _width as f32 / 4.,
35        _height as f32 / 2.,
36    )));
37
38    while is_running {
39        if event::poll(Duration::ZERO)? {
40            match event::read()? {
41                event::Event::Key(e) => {
42                    if e.code == KeyCode::Esc {
43                        is_running = false;
44                    }
45                }
46                event::Event::Resize(_, _) => {
47                    fm.reset();
48                    term.reinit(&cfg);
49                }
50                _ => {}
51            };
52        }
53
54        let delta_time = SystemTime::now().duration_since(time).unwrap();
55        fm.update(time, delta_time);
56        time = SystemTime::now();
57
58        term.render(&fm, &cfg);
59        term.print(&mut stdout, &cfg);
60
61        if delta_time < Duration::from_secs_f32(0.05) {
62            let rem = Duration::from_secs_f32(0.05) - delta_time;
63            sleep(rem);
64        }
65    }
66
67    execute!(stdout, cursor::Show, terminal::LeaveAlternateScreen)?;
68    terminal::disable_raw_mode()?;
69
70    Ok(())
71}
72
73fn gen_vortex_firework(center: Vec2) -> Firework {
74    let colors = vec![
75        (6, 55, 63),
76        (24, 90, 96),
77        (47, 123, 119),
78        (92, 174, 166),
79        (200, 255, 255),
80    ];
81    let mut particles = Vec::new();
82    for p in gen_points_circle(30, 45).iter() {
83        particles.push(ParticleConfig::new(
84            center + *p,
85            Vec2::new((*p).y, -(*p).x).normalize() * 15.,
86            thread_rng().gen_range(28..40),
87            Duration::from_secs_f32(thread_rng().gen_range(4.5..7.0)),
88            *colors.iter().choose(&mut thread_rng()).unwrap(),
89        ));
90    }
91    let mut config = FireworkConfig::default()
92        .with_ar_scale(0.05)
93        .with_gravity_scale(0.)
94        .with_gradient_scale(gradient)
95        .with_additional_force(move |particle| {
96            (center - particle.pos).normalize() * (1. / center.distance(particle.pos)) * 150.
97        });
98    config.set_enable_gradient(true);
99    Firework {
100        init_time: SystemTime::now(),
101        spawn_after: Duration::ZERO,
102        center,
103        particles,
104        config,
105        form: ExplosionForm::Sustained {
106            lasts: Duration::from_secs(10),
107            time_interval: Duration::from_secs_f32(0.01),
108            timer: Duration::ZERO,
109        },
110        ..Default::default()
111    }
112}
113
114fn gradient(x: f32) -> f32 {
115    if x < 0.8125 {
116        -0.4 * x + 1.1
117    } else {
118        -2. * x + 2.2
119    }
120}