use bevy::{gizmos::config::GizmoConfigGroup, prelude::*};
use crate::sequence::{Rig, SequenceAsset};
#[derive(GizmoConfigGroup, Reflect, Default)]
pub struct DirectorGizmoGroup;
const PATH_SAMPLES: usize = 48;
const KEY_RADIUS: f32 = 0.14;
const BODY_HALF: Vec3 = Vec3::new(0.14, 0.10, 0.22);
const LOOK_RAY: f32 = 1.6;
fn shot_color(index: usize) -> Color {
let hues = [200.0, 30.0, 130.0, 280.0, 60.0, 330.0];
Color::hsl(hues[index % hues.len()], 0.85, 0.6)
}
pub fn draw_sequence(gizmos: &mut Gizmos<DirectorGizmoGroup>, sequence: &SequenceAsset) {
use bevy::math::cubic_splines::{CubicBSpline, CubicCardinalSpline, CubicGenerator};
use crate::sequence::{RailKind, TargetRef};
for (index, shot) in sequence.shots.iter().enumerate() {
let color = shot_color(index);
match &shot.rig {
Rig::Keys { keys, .. } => {
if keys.len() > 1 {
let first = keys.first().unwrap().time;
let last = keys.last().unwrap().time;
let span = (last - first).max(f32::EPSILON);
let points = (0..=PATH_SAMPLES).map(|i| {
let t = first + span * i as f32 / PATH_SAMPLES as f32;
sample_keys_pos(keys, t)
});
gizmos.linestrip(points, color.with_alpha(0.8));
}
for key in keys {
gizmos.sphere(Isometry3d::from_translation(key.pos), KEY_RADIUS, color);
if let Some(rot) = key.rot {
let iso = Isometry3d::new(key.pos, rot);
gizmos.primitive_3d(
&Cuboid {
half_size: BODY_HALF,
},
iso,
color,
);
gizmos.line(
key.pos,
key.pos + rot * (Vec3::NEG_Z * LOOK_RAY),
color.with_alpha(0.5),
);
}
}
}
Rig::Rail { points, kind, .. } => {
let curve = match kind {
RailKind::CatmullRom => CubicCardinalSpline::new_catmull_rom(points.clone())
.to_curve()
.ok(),
RailKind::BSpline => CubicBSpline::new(points.clone()).to_curve().ok(),
};
if let Some(curve) = curve {
let segs = curve.segments().len() as f32;
let sampled = (0..=PATH_SAMPLES)
.map(|i| curve.position(segs * i as f32 / PATH_SAMPLES as f32));
gizmos.linestrip(sampled, color.with_alpha(0.8));
}
for point in points {
gizmos.sphere(Isometry3d::from_translation(*point), KEY_RADIUS, color);
}
}
Rig::Orbit { center, radius, .. } => {
if let TargetRef::Point(center) = center {
gizmos.sphere(
Isometry3d::from_translation(*center),
KEY_RADIUS * 1.4,
color,
);
let r = radius.sample(0.0).max(0.0);
let flat = Quat::from_rotation_x(std::f32::consts::FRAC_PI_2);
gizmos
.circle(Isometry3d::new(*center, flat), r, color.with_alpha(0.6))
.resolution(48);
}
}
}
}
}
pub fn draw_playhead(gizmos: &mut Gizmos<DirectorGizmoGroup>, pos: Vec3, rot: Quat) {
let color = Color::srgb(0.95, 0.97, 1.0);
let iso = Isometry3d::new(pos, rot);
gizmos.primitive_3d(
&Cuboid {
half_size: BODY_HALF * 1.3,
},
iso,
color,
);
gizmos.line(pos, pos + rot * (Vec3::NEG_Z * LOOK_RAY * 1.5), color);
}
fn sample_keys_pos(keys: &[crate::sequence::Key], t: f32) -> Vec3 {
if keys.len() == 1 || t <= keys[0].time {
return keys[0].pos;
}
if let Some(seg) = keys.windows(2).find(|p| t <= p[1].time) {
crate::curve::eased_segment(&seg[0], &seg[1], t).0
} else {
keys.last().unwrap().pos
}
}