use animsmith_core::config::{ClipExpectations, Pinned};
use animsmith_core::measure::measure_document;
use animsmith_core::profile::{ResolvedRoles, Role, detect_profile};
use animsmith_core::{CheckCtx, Config, MetricGrids, Severity, all_checks, run_checks};
use std::path::Path;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = Path::new(env!("CARGO_MANIFEST_DIR")).join("examples/rig.gltf");
let doc = animsmith_gltf::load(&path)?;
println!(
"loaded {} bones, {} clip(s)",
doc.skeleton.bones.len(),
doc.clips.len()
);
let roles = detect_profile(&doc.skeleton).unwrap_or_else(|| {
ResolvedRoles::from_names(
&doc.skeleton,
[
(Role::Root, "root".to_string()),
(Role::Hips, "hips".to_string()),
(Role::LeftFoot, "foot".to_string()),
],
)
});
println!("rig profile: {} ({} roles)", roles.profile, roles.len());
let mut config = Config::default();
config.clips.insert(
"walk".into(),
ClipExpectations {
looping: Some(true),
in_place: Some(true),
fps: Some(2.0), speed_mps: None,
animates_bones: Some(vec!["hips".into()]),
},
);
let grids = MetricGrids::new(&doc);
let measurements = measure_document(&grids, &roles, &config);
for (clip, m) in &measurements {
println!(
"measured '{clip}': {:.3}s, {} frames, {} animated bones",
m.duration_s,
m.frame_count,
m.animated_bones.len()
);
}
let ctx = CheckCtx::new(&grids, &roles, &config);
let findings = run_checks(&ctx, &all_checks());
for f in &findings {
println!(
" {}[{}] {}: {}",
f.severity,
f.check_id,
f.clip.as_deref().unwrap_or("-"),
f.message
);
}
let worst = findings.iter().map(|f| f.severity).max();
let exit = match worst {
Some(Severity::Error) => 1,
_ => 0,
};
println!(
"{} finding(s); gate exit code {exit} (expected 1 — see the \
deliberately wrong in_place declaration above)",
findings.len()
);
std::process::exit(exit);
}
#[allow(dead_code)]
fn speed_pin() -> Pinned {
Pinned {
value: 3.1,
tolerance: 0.25,
}
}