proof_engine/curves/
dissolve.rs1use glam::Vec2;
7use super::entity_curves::{CurveEntity, CurveType};
8use std::f32::consts::TAU;
9
10#[derive(Debug, Clone)]
12pub struct DissolveState {
13 pub active: bool,
14 pub elapsed: f32,
15 pub duration: f32,
16 pub attractor_type: DissolveAttractor,
17}
18
19#[derive(Debug, Clone, Copy, PartialEq)]
21pub enum DissolveAttractor {
22 None,
23 Lorenz,
24 Rossler,
25 Scatter,
26 Spiral,
27}
28
29impl DissolveState {
30 pub fn new(attractor: DissolveAttractor) -> Self {
31 Self { active: true, elapsed: 0.0, duration: 3.0, attractor_type: attractor }
32 }
33
34 pub fn inactive() -> Self {
35 Self { active: false, elapsed: 0.0, duration: 3.0, attractor_type: DissolveAttractor::None }
36 }
37
38 pub fn begin(&mut self, attractor: DissolveAttractor) {
40 self.active = true;
41 self.elapsed = 0.0;
42 self.attractor_type = attractor;
43 }
44
45 pub fn update(&mut self, entity: &mut CurveEntity, dt: f32) -> bool {
47 if !self.active { return false; }
48 self.elapsed += dt;
49
50 let t = (self.elapsed / self.duration).min(1.0);
51
52 entity.emission_mult = (1.0 - t).max(0.0);
54
55 for curve in &mut entity.curves {
57 curve.color.w = (1.0 - t).max(0.0);
58 }
59
60 for curve in &mut entity.curves {
62 for (i, vel) in curve.point_velocities.iter_mut().enumerate() {
63 let pt = curve.control_points[i];
64 let force = match self.attractor_type {
65 DissolveAttractor::Lorenz => lorenz_2d(pt, self.elapsed),
66 DissolveAttractor::Rossler => rossler_2d(pt, self.elapsed),
67 DissolveAttractor::Spiral => {
68 let angle = pt.y.atan2(pt.x) + 0.5;
69 Vec2::new(angle.cos(), angle.sin()) * 0.5
70 }
71 DissolveAttractor::Scatter => Vec2::ZERO,
72 DissolveAttractor::None => Vec2::ZERO,
73 };
74 *vel += force * dt;
75 }
76 }
77
78 for curve in &mut entity.curves {
80 if let CurveType::Lissajous { ref mut a, ref mut b, ref mut delta } = curve.curve_type {
81 *a += (std::f32::consts::E - *a) * dt * 0.3;
82 *b += (std::f32::consts::PI - *b) * dt * 0.3;
83 *delta += dt * 0.5;
84 }
85 }
86
87 self.elapsed >= self.duration
88 }
89
90 pub fn progress(&self) -> f32 { (self.elapsed / self.duration).min(1.0) }
91 pub fn is_done(&self) -> bool { self.elapsed >= self.duration }
92}
93
94fn lorenz_2d(pos: Vec2, t: f32) -> Vec2 {
95 let sigma = 10.0;
96 let rho = 28.0;
97 let x = pos.x * 0.1;
98 let y = pos.y * 0.1;
99 let dx = sigma * (y - x);
100 let dy = x * (rho - (t * 0.5).sin() * 5.0) - y;
101 Vec2::new(dx, dy) * 0.3
102}
103
104fn rossler_2d(pos: Vec2, t: f32) -> Vec2 {
105 let a = 0.2;
106 let x = pos.x * 0.1;
107 let y = pos.y * 0.1;
108 let z = (t * 0.3).sin() * 3.0;
109 let dx = -y - z;
110 let dy = x + a * y;
111 Vec2::new(dx, dy) * 0.4
112}