use crate::*;
#[derive(Clone, Debug, Default)]
pub struct Animation {
pub id: Option<String>,
pub name: Option<String>,
pub asset: Option<Box<Asset>>,
pub children: Vec<Animation>,
pub source: Vec<Source>,
pub sampler: Vec<Sampler>,
pub channel: Vec<Channel>,
pub extra: Vec<Extra>,
}
impl XNode for Animation {
const NAME: &'static str = "animation";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
let res = Animation {
id: element.attr("id").map(Into::into),
name: element.attr("name").map(Into::into),
asset: Asset::parse_opt_box(&mut it)?,
children: Animation::parse_list(&mut it)?,
source: Source::parse_list(&mut it)?,
sampler: Sampler::parse_list(&mut it)?,
channel: Channel::parse_list(&mut it)?,
extra: Extra::parse_many(it)?,
};
if res.sampler.is_empty() != res.channel.is_empty() {
return Err("animation: sampler and channel must be used together".into());
}
Ok(res)
}
}
impl XNodeWrite for Animation {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let mut e = Self::elem();
e.opt_attr("id", &self.id);
e.opt_attr("name", &self.name);
let e = e.start(w)?;
self.asset.write_to(w)?;
self.children.write_to(w)?;
self.source.write_to(w)?;
self.sampler.write_to(w)?;
self.channel.write_to(w)?;
self.extra.write_to(w)?;
e.end(w)
}
}
impl CollectLocalMaps for Animation {
fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
maps.insert(self);
self.children.collect_local_maps(maps);
self.source.collect_local_maps(maps);
self.sampler.collect_local_maps(maps);
}
}
impl Animation {
fn on_children<'a, E>(
&'a self,
f: &mut impl FnMut(&'a Self) -> Result<(), E>,
) -> Result<(), E> {
f(self)?;
for child in &self.children {
child.on_children(f)?
}
Ok(())
}
}
impl Traversable for Animation {
fn traverse<'a, E>(
doc: &'a Document,
mut f: impl FnMut(&'a Animation) -> Result<(), E>,
) -> Result<(), E> {
doc.iter()
.try_for_each(|e: &Animation| e.on_children(&mut f))
}
}
#[derive(Clone, Debug)]
pub struct AnimationClip {
pub id: Option<String>,
pub name: Option<String>,
pub start: f32,
pub end: Option<f32>,
pub asset: Option<Box<Asset>>,
pub instance_animation: Vec<Instance<Animation>>,
pub extra: Vec<Extra>,
}
impl AnimationClip {
pub fn new(instance_animation: Vec<Instance<Animation>>) -> Self {
assert!(!instance_animation.is_empty());
Self {
id: Default::default(),
name: Default::default(),
start: Default::default(),
end: Default::default(),
asset: Default::default(),
instance_animation,
extra: Default::default(),
}
}
}
impl XNode for AnimationClip {
const NAME: &'static str = "animation_clip";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
Ok(AnimationClip {
id: element.attr("id").map(Into::into),
name: element.attr("name").map(Into::into),
start: parse_attr(element.attr("start"))?.unwrap_or(0.),
end: parse_attr(element.attr("end"))?,
asset: Asset::parse_opt_box(&mut it)?,
instance_animation: Instance::parse_list_n::<1>(&mut it)?,
extra: Extra::parse_many(it)?,
})
}
}
impl XNodeWrite for AnimationClip {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let mut e = Self::elem();
e.opt_attr("id", &self.id);
e.opt_attr("name", &self.name);
e.print_attr("start", self.start);
e.opt_print_attr("end", &self.end);
let e = e.start(w)?;
self.asset.write_to(w)?;
self.instance_animation.write_to(w)?;
self.extra.write_to(w)?;
e.end(w)
}
}
#[derive(Clone, Debug)]
pub struct Channel {
pub source: UrlRef<Sampler>,
pub target: Address,
}
impl Channel {
pub fn new(source: Url, target: String) -> Self {
Self {
source: Ref::new(source),
target: Address(target),
}
}
}
impl XNode for Channel {
const NAME: &'static str = "channel";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let target = element.attr("target").ok_or("expecting target attr")?;
Ok(Channel {
source: parse_attr(element.attr("source"))?.ok_or("missing source attr")?,
target: Address(target.into()),
})
}
}
impl XNodeWrite for Channel {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let mut e = Self::elem();
e.print_attr("source", &self.source);
e.print_attr("target", &self.target);
e.end(w)
}
}
#[derive(Clone, Debug)]
pub struct Sampler {
pub id: Option<String>,
pub inputs: Vec<Input>,
pub interpolation: usize,
}
impl Sampler {
pub fn new(inputs: Vec<Input>) -> Self {
Self {
id: None,
interpolation: inputs
.iter()
.position(|i| i.semantic == Semantic::Interpolation)
.expect("sampler: missing INTERPOLATION input"),
inputs,
}
}
}
impl XNode for Sampler {
const NAME: &'static str = "sampler";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
let inputs = Input::parse_list(&mut it)?;
let res = Sampler {
id: element.attr("id").map(Into::into),
interpolation: inputs
.iter()
.position(|i| i.semantic == Semantic::Interpolation)
.ok_or("sampler: missing INTERPOLATION input")?,
inputs,
};
finish(res, it)
}
}
impl XNodeWrite for Sampler {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let mut e = Self::elem();
e.opt_attr("id", &self.id);
let e = e.start(w)?;
self.inputs.write_to(w)?;
e.end(w)
}
}
impl CollectLocalMaps for Sampler {
fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
maps.insert(self)
}
}
impl Traversable for Sampler {
fn traverse<'a, E>(
doc: &'a Document,
mut f: impl FnMut(&'a Self) -> Result<(), E>,
) -> Result<(), E>
where
Self: 'a,
{
doc.iter()
.try_for_each(|lib: &Animation| lib.sampler.iter().try_for_each(&mut f))
}
}
impl Sampler {
pub fn interpolation_input(&self) -> &Input {
&self.inputs[self.interpolation]
}
}