use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use crate::ecs::animation::components::{AnimationClip, AnimationPlayer};
use super::asset_uuid::AssetUuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneAnimationClipRef {
#[serde(default)]
pub uuid: Option<AssetUuid>,
#[serde(default)]
pub path: Option<String>,
#[serde(default)]
pub name: Option<String>,
}
impl SceneAnimationClipRef {
pub fn from_uuid(uuid: AssetUuid) -> Self {
Self {
uuid: Some(uuid),
path: None,
name: None,
}
}
pub fn from_path(path: impl Into<String>) -> Self {
Self {
uuid: None,
path: Some(path.into()),
name: None,
}
}
pub fn from_name(name: impl Into<String>) -> Self {
Self {
uuid: None,
path: None,
name: Some(name.into()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneAnimationPlayer {
#[serde(default)]
pub clips: Vec<AnimationClip>,
#[serde(default)]
pub clip_refs: Vec<SceneAnimationClipRef>,
#[serde(default)]
pub current_clip: Option<usize>,
#[serde(default)]
pub time: f32,
#[serde(default = "default_animation_speed")]
pub speed: f32,
#[serde(default = "default_true")]
pub looping: bool,
#[serde(default)]
pub playing: bool,
#[serde(default)]
pub play_all: bool,
#[serde(default)]
pub bone_name_to_node: HashMap<String, AssetUuid>,
}
fn default_animation_speed() -> f32 {
1.0
}
fn default_true() -> bool {
true
}
impl Default for SceneAnimationPlayer {
fn default() -> Self {
Self {
clips: Vec::new(),
clip_refs: Vec::new(),
current_clip: None,
time: 0.0,
speed: 1.0,
looping: true,
playing: false,
play_all: false,
bone_name_to_node: HashMap::new(),
}
}
}
impl SceneAnimationPlayer {
pub fn new(clips: Vec<AnimationClip>) -> Self {
Self {
clips,
..Default::default()
}
}
pub fn with_current_clip(mut self, clip_index: usize) -> Self {
self.current_clip = Some(clip_index);
self
}
pub fn with_playing(mut self, playing: bool) -> Self {
self.playing = playing;
self
}
pub fn with_looping(mut self, looping: bool) -> Self {
self.looping = looping;
self
}
pub fn with_speed(mut self, speed: f32) -> Self {
self.speed = speed;
self
}
pub fn to_animation_player(&self) -> AnimationPlayer {
AnimationPlayer {
clips: self.clips.clone(),
current_clip: self.current_clip,
time: self.time,
speed: self.speed,
looping: self.looping,
playing: self.playing,
play_all: self.play_all,
node_index_to_entity: HashMap::new(),
bone_name_to_entity: HashMap::new(),
blend_from_clip: None,
blend_from_time: 0.0,
blend_factor: 1.0,
blend_duration: 0.0,
}
}
pub fn to_animation_player_with_resolved_clips(
&self,
asset_registry: Option<&super::registry::AssetRegistry>,
warnings: &mut Vec<String>,
) -> AnimationPlayer {
let mut clips = self.clips.clone();
for clip_ref in &self.clip_refs {
let path = if let Some(uuid) = clip_ref.uuid {
asset_registry.and_then(|registry| registry.resolve_uuid(uuid))
} else if let Some(ref path_str) = clip_ref.path {
Some(std::path::PathBuf::from(path_str))
} else if let Some(ref name) = clip_ref.name {
asset_registry
.and_then(|registry| registry.resolve_name(name))
.and_then(|uuid| {
asset_registry.and_then(|registry| registry.resolve_uuid(uuid))
})
} else {
None
};
if let Some(ref path) = path {
match load_animation_clip_from_path(path) {
Ok(clip) => clips.push(clip),
Err(error) => warnings.push(format!(
"Failed to load animation clip from {}: {}",
path.display(),
error
)),
}
} else {
warnings.push(format!(
"Could not resolve animation clip reference: {:?}",
clip_ref
));
}
}
AnimationPlayer {
clips,
current_clip: self.current_clip,
time: self.time,
speed: self.speed,
looping: self.looping,
playing: self.playing,
play_all: self.play_all,
node_index_to_entity: HashMap::new(),
bone_name_to_entity: HashMap::new(),
blend_from_clip: None,
blend_from_time: 0.0,
blend_factor: 1.0,
blend_duration: 0.0,
}
}
}
fn load_animation_clip_from_path(path: &std::path::Path) -> Result<AnimationClip, String> {
let data = std::fs::read(path).map_err(|error| error.to_string())?;
match path.extension().and_then(|extension| extension.to_str()) {
Some("json") => serde_json::from_slice(&data).map_err(|error| error.to_string()),
Some("bin") => {
let decompressed =
lz4_flex::decompress_size_prepended(&data).map_err(|error| error.to_string())?;
bincode::deserialize(&decompressed).map_err(|error| error.to_string())
}
_ => bincode::deserialize(&data).map_err(|error| error.to_string()),
}
}
impl From<&AnimationPlayer> for SceneAnimationPlayer {
fn from(player: &AnimationPlayer) -> Self {
Self {
clips: player.clips.clone(),
clip_refs: Vec::new(),
current_clip: player.current_clip,
time: player.time,
speed: player.speed,
looping: player.looping,
playing: player.playing,
play_all: player.play_all,
bone_name_to_node: HashMap::new(),
}
}
}