use crate::gfx::pose_blend::{PoseBlend, blend_locals_in_place};
use crate::gfx::pose_scratch::PoseScratch;
use crate::gfx::skeleton::{AnimationClip, Skeleton};
use crate::gfx::transform::Mat4;
use crate::math::fract;
use alloc::vec::Vec;
use super::{CompiledGraph, CompiledState, GraphCursor};
pub fn sample_graph_pose_into<'a>(
graph: &CompiledGraph,
cursor: &GraphCursor,
params: &[f32],
clip_at: impl Fn(usize) -> &'a AnimationClip,
skeleton: &Skeleton,
scratch: &mut PoseScratch,
) {
let Some(fade) = &cursor.fade else {
sample_state_into(
&graph.states[cursor.state],
cursor.clock,
params,
&clip_at,
skeleton,
&mut scratch.locals,
BlendBufs {
clip: &mut scratch.clip,
weights: &mut scratch.weights,
},
);
return;
};
sample_state_into(
&graph.states[fade.from_state],
fade.from_clock,
params,
&clip_at,
skeleton,
&mut scratch.locals,
BlendBufs {
clip: &mut scratch.clip,
weights: &mut scratch.weights,
},
);
sample_state_into(
&graph.states[cursor.state],
cursor.clock,
params,
&clip_at,
skeleton,
&mut scratch.aux,
BlendBufs {
clip: &mut scratch.clip,
weights: &mut scratch.weights,
},
);
blend_locals_in_place(&mut scratch.locals, &scratch.aux, fade.progress());
}
struct BlendBufs<'a> {
clip: &'a mut Vec<Mat4>,
weights: &'a mut Vec<f32>,
}
fn sample_state_into<'a>(
state: &CompiledState,
clock: f32,
params: &[f32],
clip_at: &impl Fn(usize) -> &'a AnimationClip,
skeleton: &Skeleton,
out: &mut Vec<Mat4>,
bufs: BlendBufs<'_>,
) {
state.play.weights_into(params, bufs.weights);
let members = state.play.members();
let mut fold = PoseBlend::new(out);
for (member, &w) in members.iter().zip(bufs.weights.iter()) {
if w <= 0.0 {
continue;
}
let t = member_time(state, member.duration_secs, clock);
clip_at(member.clip).sample_looped_into(t, state.looping, skeleton, bufs.clip);
fold.add(bufs.clip, w);
}
if !fold.seeded() {
out.clear();
out.extend(skeleton.joints().iter().map(|j| j.bind.to_matrix()));
}
}
fn member_time(state: &CompiledState, member_duration: f32, clock: f32) -> f32 {
if state.play.sync() {
let phase = if state.looping {
fract(clock)
} else {
clock.clamp(0.0, 1.0)
};
phase * member_duration
} else {
clock
}
}