use std::collections::HashMap;
use std::rc::Rc;
use rustc_serialize::{Decodable, Decoder};
use animation::AnimationClip;
use transform::{Transform, FromTransform};
use blend_tree::{AnimBlendTree, BlendTreeNodeDef, ClipId};
use skeleton::Skeleton;
const MAX_JOINTS: usize = 64;
pub struct AnimationState<T: Transform> {
pub blend_tree: AnimBlendTree<T>,
pub transitions: Vec<AnimationTransition>,
}
#[derive(Debug, Clone, RustcDecodable)]
pub struct AnimationTransition {
pub target_state: String,
pub condition: TransitionCondition,
pub duration: f32,
}
#[derive(Debug, Clone, RustcDecodable)]
pub struct TransitionCondition {
pub parameter: String,
pub operator: Operator,
pub value: f32,
}
impl TransitionCondition {
pub fn is_true(&self, parameters: &HashMap<String, f32>) -> bool {
match self.operator {
Operator::LessThan => parameters[&self.parameter[..]] < self.value,
Operator::GreaterThan => parameters[&self.parameter[..]] > self.value,
Operator::LessThanEqual => parameters[&self.parameter[..]] <= self.value,
Operator::GreaterThanEqual => parameters[&self.parameter[..]] >= self.value,
Operator::Equal => parameters[&self.parameter[..]] == self.value,
Operator::NotEqual => parameters[&self.parameter[..]] != self.value,
}
}
}
#[derive(Debug, Clone)]
pub enum Operator {
LessThan,
LessThanEqual,
GreaterThan,
GreaterThanEqual,
Equal,
NotEqual,
}
impl Decodable for Operator {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Operator, D::Error> {
match &decoder.read_str()?[..] {
"<" => Ok(Operator::LessThan),
">" => Ok(Operator::GreaterThan),
"<=" => Ok(Operator::LessThanEqual),
">=" => Ok(Operator::GreaterThanEqual),
"=" => Ok(Operator::Equal),
"!=" => Ok(Operator::NotEqual),
_ => Ok(Operator::Equal), }
}
}
#[derive(Clone, Debug, RustcDecodable)]
pub struct AnimationControllerDef {
pub name: String,
pub parameters: Vec<String>,
pub states: Vec<AnimationStateDef>,
pub initial_state: String,
}
#[derive(Clone, Debug)]
pub struct AnimationStateDef {
pub name: String,
pub blend_tree: BlendTreeNodeDef,
pub transitions: Vec<AnimationTransition>,
}
impl Decodable for AnimationStateDef {
fn decode<D: Decoder>(decoder: &mut D) -> Result<AnimationStateDef, D::Error> {
decoder.read_struct("root", 0, |decoder| {
let name = decoder.read_struct_field("name", 0, |decoder| {
Ok(decoder.read_str()?)
})?;
let blend_tree = decoder.read_struct_field("blend_tree", 0, Decodable::decode)?;
let transitions = decoder.read_struct_field("transitions", 0, |decoder| {
decoder.read_seq(|decoder, len| {
let mut transitions = Vec::new();
for i in 0 .. len {
transitions.push(decoder.read_seq_elt(i, Decodable::decode)?);
}
Ok(transitions)
})
})?;
Ok(AnimationStateDef {
name: name,
blend_tree: blend_tree,
transitions: transitions,
})
})
}
}
pub struct AnimationController<T: Transform> {
parameters: HashMap<String, f32>,
skeleton: Rc<Skeleton>,
local_clock: f64,
playback_speed: f64,
states: HashMap<String, AnimationState<T>>,
current_state: String,
transition: Option<(f64, AnimationTransition)>,
}
impl<T: Transform> AnimationController<T> {
pub fn new(controller_def: AnimationControllerDef, skeleton: Rc<Skeleton>, animations: &HashMap<ClipId, Rc<AnimationClip<T>>>) -> AnimationController<T> {
let mut parameters = HashMap::new();
for parameter in controller_def.parameters.iter() {
parameters.insert(parameter.clone(), 0.0);
};
let mut states = HashMap::new();
for state_def in controller_def.states.iter() {
let mut blend_tree = AnimBlendTree::from_def(state_def.blend_tree.clone(), animations, skeleton.clone());
blend_tree.synchronize(0.0, ¶meters);
states.insert(state_def.name.clone(), AnimationState {
blend_tree: blend_tree,
transitions: state_def.transitions.clone()
});
}
AnimationController {
parameters: parameters,
skeleton: skeleton.clone(),
local_clock: 0.0,
playback_speed: 1.0,
states: states,
current_state: controller_def.initial_state,
transition: None,
}
}
pub fn update(&mut self, delta_time: f64) {
self.local_clock += delta_time * self.playback_speed;
}
fn update_state(&mut self, ext_dt: f64) {
match self.transition.clone() {
Some((ref start_time, ref transition)) => {
if self.local_clock + ext_dt >= start_time + transition.duration as f64{
self.current_state = transition.target_state.clone();
self.transition = None;
}
},
None => {
let current_state = &self.states[&self.current_state[..]];
for transition in current_state.transitions.iter() {
if transition.condition.is_true(&self.parameters) {
self.transition = Some((self.local_clock + ext_dt, transition.clone()));
break;
}
}
}
}
}
pub fn set_playback_speed(&mut self, speed: f64) {
self.playback_speed = speed;
}
pub fn set_param_value(&mut self, name: &str, value: f32) {
self.parameters.insert(name.to_string(), value); }
pub fn get_param_value(&self, name: &str) -> f32 {
self.parameters[name]
}
pub fn get_parameters(&self) -> &HashMap<String, f32> {
&self.parameters
}
pub fn get_output_pose<TOutput: Transform + FromTransform<T>>(&mut self, ext_dt: f64, output_poses: &mut [TOutput]) {
self.update_state(ext_dt);
let elapsed_time = self.local_clock + ext_dt * self.playback_speed;
let mut local_poses = [ T::identity(); MAX_JOINTS ];
{
let current_state = self.states.get_mut(&self.current_state[..]).unwrap();
current_state.blend_tree.synchronize(elapsed_time as f32, &self.parameters);
current_state.blend_tree.get_output_pose(elapsed_time as f32, &self.parameters, &mut local_poses[..]);
}
if let Some((transition_start_time, ref transition)) = self.transition {
let mut target_poses = [ T::identity(); MAX_JOINTS ];
let target_state = self.states.get_mut(&transition.target_state[..]).unwrap();
target_state.blend_tree.synchronize(elapsed_time as f32, &self.parameters);
target_state.blend_tree.get_output_pose(elapsed_time as f32, &self.parameters, &mut target_poses[..]);
let blend_parameter = ((self.local_clock + ext_dt - transition_start_time) / transition.duration as f64) as f32;
for i in 0 .. output_poses.len() {
let pose_1 = &mut local_poses[i];
let pose_2 = target_poses[i];
*pose_1 = pose_1.lerp(pose_2, blend_parameter);
}
}
self.calculate_global_poses(&local_poses[..], output_poses);
}
fn calculate_global_poses<TOutput: Transform + FromTransform<T>>(
&self,
local_poses: &[T],
global_poses: &mut [TOutput],
) {
for (joint_index, joint) in self.skeleton.joints.iter().enumerate() {
let parent_pose = if !joint.is_root() {
global_poses[joint.parent_index as usize]
} else {
TOutput::identity()
};
let local_pose = local_poses[joint_index];
global_poses[joint_index] = parent_pose.concat(TOutput::from_transform(local_pose));
}
}
}