Revert "Add retargeted Skate idle and carving clip replacements"

This reverts commit 0f1ccd09ad.
This commit is contained in:
chazmm committed 2026-09-07 01:30:28 +01:00
1 parent 0f1ccd09ad
commit 0abe89a0c0
4 files changed
+2 -162

No files matched your search

+1 -12
View File
@@ -12,31 +12,21 @@ use skate_data::{
animation_frames::{AnimationFrames, ClipFrames, SampleWords},
};
use std::path::Path;
mod custom_riding;
pub(crate) struct PoseEvaluator {
pub frames: AnimationFrames,
riding: custom_riding::Replacements,
}
impl PoseEvaluator {
pub fn load(asset_root: &Path) -> Result<Self, String> {
let mut result = Self::from_banks(&AnimationBanks::load(asset_root)?)?;
result.load_riding(asset_root)?;
Ok(result)
Self::from_banks(&AnimationBanks::load(asset_root)?)
}
pub fn from_banks(banks: &AnimationBanks) -> Result<Self, String> {
Ok(Self {
frames: AnimationFrames::from_banks(banks)?,
riding: Default::default(),
})
}
pub fn load_riding(&mut self, root: &Path) -> Result<(), String> {
self.riding = custom_riding::Replacements::load(root, &self.frames)?;
Ok(())
}
/// Executes the ordered stock tree. This uses the native immediate ACS
/// arithmetic; the host does not recreate packed animation job commands.
pub fn evaluate(&self, commands: &[PoseCommand]) -> Result<Vec<Sqt>, String> {
@@ -92,7 +82,6 @@ impl PoseEvaluator {
} => {
let clip = self.frames.clip(name)?;
let mut pose = sample_clip(clip, *time)?;
self.riding.apply(clip, *time, &mut pose);
if self.frames.has_trajectory {
let previous = sample_bone(clip, *previous_time, 0)?;
pose[0] = pose_trajectory::delta(
@@ -1,135 +0,0 @@
//! Optional retargeted riding samples inside the existing stock playback tree.
//! Graph selection, channel weights, trajectory, board and mirroring stay stock.
use super::*;
use serde::Deserialize;
use std::collections::BTreeMap;
#[derive(Default)]
pub(super) struct Replacements(BTreeMap<String, Replacement>);
#[derive(Deserialize)]
struct File {
version: u32,
bone_names: Vec<String>,
replacements: Vec<Replacement>,
}
#[derive(Deserialize)]
struct Replacement {
name: String,
fps: f32,
frames: Vec<Vec<[f32; 10]>>,
}
impl Replacements {
pub fn load(root: &Path, frames: &AnimationFrames) -> Result<Self, String> {
let path = root.join("private/custom/riding.json");
let text = match std::fs::read_to_string(&path) {
Ok(text) => text,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(Self::default()),
Err(e) => return Err(format!("{}: {e}", path.display())),
};
let file: File =
serde_json::from_str(&text).map_err(|e| format!("Riding replacements: {e}"))?;
if file.version != 1 || file.bone_names != frames.bone_names {
return Err("Riding replacement skeleton differs from the stock rig".into());
}
let mut result = BTreeMap::new();
for c in file.replacements {
let approved = ["R_IDLE_HCOM_000", "R_IDLE_HCOM_N100", "R_IDLE_HCOM_P100"]
.contains(&c.name.as_str())
|| ["MED", "ML", "LNG"]
.iter()
.any(|prefix| (0..10).any(|i| c.name == format!("{prefix}_CRV_POSE_{i}")));
if !approved
|| !c.fps.is_finite()
|| c.fps <= 0.
|| c.frames.len() < 2
|| c.frames.iter().any(|f| {
f.len() != frames.bone_names.len()
|| f.iter().any(|s| {
!s.iter().all(|v| v.is_finite())
|| s[..3].iter().any(|v| *v <= 0.)
|| (s[3..7].iter().map(|v| v * v).sum::<f32>() - 1.).abs() > 0.002
})
})
{
return Err(format!("Invalid riding replacement {}", c.name));
}
frames.clip(&c.name)?;
let name = c.name.clone();
if result.insert(name.clone(), c).is_some() {
return Err(format!("Duplicate riding replacement {name}"));
}
}
Ok(Self(result))
}
pub fn apply(&self, clip: &ClipFrames, time: f32, pose: &mut [Sqt]) {
let Some(c) = self.0.get(&clip.name) else {
return;
};
let duration = (clip.frames.len() - 1) as f32 / f32::from_bits(clip.fps_bits);
let frame = (time / duration.max(0.0001)).clamp(0., 1.) * (c.frames.len() - 1) as f32;
let i = frame.floor() as usize;
let j = (i + 1).min(c.frames.len() - 1);
for bone in (1..25).chain(32..36) {
let decode = |s: [f32; 10]| sqt(s.map(f32::to_bits));
let weight = pose[bone].translation[3];
pose[bone] = pose_blend::blend_sample(
decode(c.frames[i][bone]),
decode(c.frames[j][bone]),
frame.fract(),
);
pose[bone].translation[3] = weight;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore = "requires private stock banks and retargeted riding clips"]
fn riding_replacements_keep_board_trajectory_and_unrelated_clips_stock() {
let root = std::env::var_os("SKATE3_ASSET_ROOT").unwrap();
let banks = AnimationBanks::load(Path::new(&root)).unwrap();
let stock = PoseEvaluator::from_banks(&banks).unwrap();
let mut custom = PoseEvaluator::from_banks(&banks).unwrap();
custom.load_riding(Path::new(&root)).unwrap();
assert_eq!(custom.riding.0.len(), 33);
let command = |name: &str, time| PoseCommand::Clip {
name: name.into(),
time,
previous_time: 0.,
loops: 0,
};
for name in custom.riding.0.keys() {
let clip = custom.frames.clip(name).unwrap();
for fraction in [0., 0.25, 0.5, 1.] {
let time =
fraction * (clip.frames.len() - 1) as f32 / f32::from_bits(clip.fps_bits);
let a = stock.evaluate(&[command(name, time)]).unwrap();
let b = custom.evaluate(&[command(name, time)]).unwrap();
for i in std::iter::once(0).chain(25..32) {
assert_eq!(a[i], b[i], "{name} changed board/trajectory bone {i}");
}
for (a, b) in a.iter().zip(&b) {
assert_eq!(a.translation[3], b.translation[3]);
}
assert_ne!(a[5], b[5], "{name} did not replace torso");
assert!(b.iter().all(|s| {
s.rotation
.iter()
.chain(&s.translation)
.all(|v| v.is_finite())
}));
}
}
for name in [
"R_IDLE_LCOM_000",
"R_IDLE_SPEEDTUCK_N_0_CYC",
"R_CRPUSHHSP_HSTR_LEFT_0_CYC1",
] {
assert_eq!(
stock.evaluate(&[command(name, 0.2)]).unwrap(),
custom.evaluate(&[command(name, 0.2)]).unwrap()
);
}
}
}
+1 -2
View File
@@ -82,8 +82,7 @@ impl SkaterAnimation {
pro_skater: &[u8],
) -> Result<Self, String> {
let banks = skate_data::animation_banks::AnimationBanks::load(root)?;
let mut evaluator = PoseEvaluator::from_banks(&banks)?;
evaluator.load_riding(root)?;
let evaluator = PoseEvaluator::from_banks(&banks)?;
let state = state::AnimationState::new(true);
let count = evaluator.frames.bone_names.len();
let mut motion = MotionHost::from_graph(