use crate::orbs::engine::{
core::{Dot, Frame, frac, make_proj, radius_scale, with_unit_circle},
profiles::{MAX_LANES, MAX_PARTICLES, MAX_SEGS, ModeOpts, count_usize},
};
use std::f32::consts::PI;
pub fn draw_focus_into(size: f32, t: f32, o: &ModeOpts, out: &mut Frame) {
let center = size / 2.0;
let extent = size * 0.38 * o.spread.unwrap_or(1.0);
let lanes = count_usize(o.lanes, 6.0, 1, MAX_LANES as usize);
let segs = count_usize(o.segs, 12.0, 1, MAX_SEGS as usize);
let core_n = count_usize(o.particles, 5.0, 1, MAX_PARTICLES as usize);
let rs = radius_scale(size, o.rs_pow.unwrap_or(0.6));
let r_base = o.r_base.unwrap_or(0.9);
let r_depth = o.r_depth.unwrap_or(1.25);
let total = lanes.saturating_mul(segs).saturating_add(core_n);
out.dots.reserve(total);
let openness = 0.5 + 0.5 * (t * 0.9).sin();
let inner = 0.12 + 0.2 * openness;
let rotation = t * 0.11;
let inv_segs = 1.0 / segs as f32;
with_unit_circle(lanes, |directions| {
for (lane, direction) in directions.iter().enumerate() {
for i in 0..segs {
let u = (i as f32 + 0.5) * inv_segs;
let radial = inner + (1.0 - inner) * u;
let curl = (0.88 - 0.24 * openness) * (1.0 - u).powf(1.25);
let twist = rotation + curl;
let (st, ct) = twist.sin_cos();
let dx = direction[0] * ct - direction[1] * st;
let dy = direction[0] * st + direction[1] * ct;
let inner_weight = 1.0 - u;
let shimmer = 0.96 + 0.05 * (t * 1.4 + lane as f32 * 0.8).sin();
out.dots.push(
Dot::new(
center + dx * extent * radial,
center + dy * extent * radial,
0.0,
(r_base + r_depth * inner_weight) * shimmer * rs,
0.12 + 0.52 * u,
)
.with_a(0.48 + 0.52 * (PI * u).sin()),
);
}
}
});
let core_radius = size * (0.035 + 0.004 * (t * 1.5).sin());
with_unit_circle(core_n, |circle| {
for p in circle {
out.dots.push(Dot::new(
center + p[0] * core_radius,
center + p[1] * core_radius,
0.0,
(r_base + r_depth * 1.15) * rs,
0.08,
));
}
});
}
pub fn draw_gyroscope_into(size: f32, t: f32, o: &ModeOpts, out: &mut Frame) {
let center = size / 2.0;
let radius = size * 0.385 * o.spread.unwrap_or(1.0);
let rings = count_usize(o.lanes, 3.0, 1, MAX_LANES as usize).min(6);
let segs = count_usize(o.segs, 24.0, 3, MAX_SEGS as usize);
let rs = radius_scale(size, o.rs_pow.unwrap_or(0.6));
let r_base = o.r_base.unwrap_or(0.8);
let r_depth = o.r_depth.unwrap_or(1.5);
let proj = make_proj(t * 0.055, 0.18, center, center, radius);
out.dots
.reserve(rings.saturating_mul(segs.saturating_add(2)));
with_unit_circle(segs, |circle| {
for ring in 0..rings {
let spread = if rings > 1 {
ring as f32 / (rings - 1) as f32 - 0.5
} else {
0.0
};
let tilt_x = spread * 1.55 + 0.12 * (t * 0.16 + ring as f32).sin();
let tilt_y = ring as f32 * PI / rings as f32 + 0.32;
let (sx, cx) = tilt_x.sin_cos();
let (sy, cy) = tilt_y.sin_cos();
let direction = if ring % 2 == 0 { 1.0 } else { -1.0 };
let orient = |ca: f32, sa: f32| {
let y1 = sa * cx;
let z1 = sa * sx;
(ca * cy + z1 * sy, y1, -ca * sy + z1 * cy)
};
for p in circle {
let (x, y, z) = orient(p[0], p[1]);
let (px, py, depth_z) = proj.project(x, y, z);
let depth = (depth_z + 1.0) * 0.5;
out.dots.push(
Dot::new(
px,
py,
depth_z,
(r_base * 0.9 + r_depth * 0.5 * depth) * rs,
0.62 - 0.34 * depth,
)
.with_a(0.34 + 0.4 * depth),
);
}
let travel =
t * (0.72 + ring as f32 * 0.08) * direction + ring as f32 * 2.0 * PI / rings as f32;
for (trail, offset) in [0.0, -0.22 * direction].into_iter().enumerate() {
let (sa, ca) = (travel + offset).sin_cos();
let (x, y, z) = orient(ca, sa);
let (px, py, depth_z) = proj.project(x, y, z);
let depth = (depth_z + 1.0) * 0.5;
let strength = if trail == 0 { 1.0 } else { 0.48 };
out.dots.push(
Dot::new(
px,
py,
depth_z + 0.002,
(r_base + r_depth * depth + 1.65 * strength) * rs,
0.44 - 0.42 * depth - 0.2 * strength,
)
.with_a((0.55 + 0.45 * depth) * strength),
);
}
}
});
}
pub fn draw_echo_into(size: f32, t: f32, o: &ModeOpts, out: &mut Frame) {
let center = size / 2.0;
let extent = size * 0.4 * o.spread.unwrap_or(1.0);
let rings = count_usize(o.lanes, 4.0, 1, MAX_LANES as usize);
let segs = count_usize(o.segs, 18.0, 3, MAX_SEGS as usize);
let core_n = count_usize(o.particles, 3.0, 1, MAX_PARTICLES as usize);
let rs = radius_scale(size, o.rs_pow.unwrap_or(0.6));
let r_base = o.r_base.unwrap_or(0.85);
let r_depth = o.r_depth.unwrap_or(1.05);
out.dots
.reserve(rings.saturating_mul(segs).saturating_add(core_n));
with_unit_circle(segs, |circle| {
for ring in 0..rings {
let phase = frac(t * 0.14 + ring as f32 / rings as f32);
let radius = extent * (0.13 + 0.87 * phase);
let life = (PI * phase).sin().max(0.0);
let turn = ring as f32 * 0.37 - t * 0.1;
let (st, ct) = turn.sin_cos();
for p in circle {
let x = p[0] * ct - p[1] * st;
let y = p[0] * st + p[1] * ct;
out.dots.push(
Dot::new(
center + x * radius,
center + y * radius,
0.0,
(r_base + r_depth * (1.0 - phase)) * rs,
0.18 + 0.52 * phase,
)
.with_a(life.powf(0.58)),
);
}
}
});
let core_radius = size * 0.025;
with_unit_circle(core_n, |circle| {
for p in circle {
out.dots.push(Dot::new(
center + p[0] * core_radius,
center + p[1] * core_radius,
0.0,
(r_base + r_depth * 1.4) * rs,
0.06,
));
}
});
}