use crate::model::*;
use glam::Vec3;
use std::f64::consts::TAU;
pub const WALK_KEYS: usize = 33;
pub const WALK_FOOT_AMPLITUDE: f32 = 0.05;
pub const WALK_STRIDE: f32 = 0.15;
pub struct WalkBones {
pub hips: &'static str,
pub left_foot: &'static str,
pub right_foot: &'static str,
}
impl WalkBones {
pub fn skeleton(&self) -> Skeleton {
let foot = |name: &str, x: f32| Bone {
name: name.into(),
parent: Some(0),
rest: Transform {
translation: Vec3::new(x, -1.0, 0.0),
..Transform::IDENTITY
},
inverse_bind: None,
};
Skeleton {
bones: vec![
Bone {
name: self.hips.into(),
parent: None,
rest: Transform {
translation: Vec3::new(0.0, 1.0, 0.0),
..Transform::IDENTITY
},
inverse_bind: None,
},
foot(self.left_foot, 0.1),
foot(self.right_foot, -0.1),
],
}
}
}
pub fn foot_track(
bone: BoneId,
rest: Vec3,
sign: f32,
periods: f64,
stride: f32,
sin: fn(f64) -> f64,
) -> Track {
let times: Vec<f32> = (0..WALK_KEYS)
.map(|k| k as f32 / (WALK_KEYS - 1) as f32)
.collect();
let values: Vec<Vec3> = (0..WALK_KEYS)
.map(|k| {
let theta = periods * TAU * k as f64 / (WALK_KEYS - 1) as f64;
let swing = sin(theta) as f32;
rest + Vec3::new(
0.0,
sign * WALK_FOOT_AMPLITUDE * swing,
sign * stride * swing,
)
})
.collect();
Track {
bone,
property: Property::Translation,
interpolation: Interpolation::Linear,
times,
values: TrackValues::Vec3s(values),
}
}
pub fn walk_doc(
bones: &WalkBones,
clip: &str,
periods: f64,
stride: f32,
sin: fn(f64) -> f64,
) -> Document {
let skeleton = bones.skeleton();
let tracks = vec![
foot_track(
1,
skeleton.bones[1].rest.translation,
1.0,
periods,
stride,
sin,
),
foot_track(
2,
skeleton.bones[2].rest.translation,
-1.0,
periods,
stride,
sin,
),
];
Document {
skeleton,
clips: vec![Clip {
name: clip.into(),
duration_s: 1.0,
tracks,
}],
assets: Default::default(),
source: SourceInfo::default(),
}
}