1use crate::*;
2
3#[derive(Clone, Debug, Default)]
5pub struct Animation {
6 pub id: Option<String>,
8 pub name: Option<String>,
10 pub asset: Option<Box<Asset>>,
12 pub children: Vec<Animation>,
14 pub source: Vec<Source>,
17 pub sampler: Vec<Sampler>,
19 pub channel: Vec<Channel>,
21 pub extra: Vec<Extra>,
23}
24
25impl XNode for Animation {
26 const NAME: &'static str = "animation";
27 fn parse(element: &Element) -> Result<Self> {
28 debug_assert_eq!(element.name(), Self::NAME);
29 let mut it = element.children().peekable();
30 let res = Animation {
31 id: element.attr("id").map(Into::into),
32 name: element.attr("name").map(Into::into),
33 asset: Asset::parse_opt_box(&mut it)?,
34 children: Animation::parse_list(&mut it)?,
35 source: Source::parse_list(&mut it)?,
36 sampler: Sampler::parse_list(&mut it)?,
37 channel: Channel::parse_list(&mut it)?,
38 extra: Extra::parse_many(it)?,
39 };
40 if res.sampler.is_empty() != res.channel.is_empty() {
46 return Err("animation: sampler and channel must be used together".into());
47 }
48 Ok(res)
49 }
50}
51
52impl XNodeWrite for Animation {
53 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
54 let mut e = Self::elem();
55 e.opt_attr("id", &self.id);
56 e.opt_attr("name", &self.name);
57 let e = e.start(w)?;
58 self.asset.write_to(w)?;
59 self.children.write_to(w)?;
60 self.source.write_to(w)?;
61 self.sampler.write_to(w)?;
62 self.channel.write_to(w)?;
63 self.extra.write_to(w)?;
64 e.end(w)
65 }
66}
67
68impl CollectLocalMaps for Animation {
69 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
70 maps.insert(self);
71 self.children.collect_local_maps(maps);
72 self.source.collect_local_maps(maps);
73 self.sampler.collect_local_maps(maps);
74 }
75}
76
77impl Animation {
78 fn on_children<'a, E>(
79 &'a self,
80 f: &mut impl FnMut(&'a Self) -> Result<(), E>,
81 ) -> Result<(), E> {
82 f(self)?;
83 for child in &self.children {
84 child.on_children(f)?
85 }
86 Ok(())
87 }
88}
89
90impl Traversable for Animation {
91 fn traverse<'a, E>(
92 doc: &'a Document,
93 mut f: impl FnMut(&'a Animation) -> Result<(), E>,
94 ) -> Result<(), E> {
95 doc.iter()
96 .try_for_each(|e: &Animation| e.on_children(&mut f))
97 }
98}
99
100#[derive(Clone, Debug)]
102pub struct AnimationClip {
103 pub id: Option<String>,
105 pub name: Option<String>,
107 pub start: f32,
112 pub end: Option<f32>,
115 pub asset: Option<Box<Asset>>,
117 pub instance_animation: Vec<Instance<Animation>>,
119 pub extra: Vec<Extra>,
121}
122
123impl AnimationClip {
124 pub fn new(instance_animation: Vec<Instance<Animation>>) -> Self {
126 assert!(!instance_animation.is_empty());
127 Self {
128 id: Default::default(),
129 name: Default::default(),
130 start: Default::default(),
131 end: Default::default(),
132 asset: Default::default(),
133 instance_animation,
134 extra: Default::default(),
135 }
136 }
137}
138
139impl XNode for AnimationClip {
140 const NAME: &'static str = "animation_clip";
141 fn parse(element: &Element) -> Result<Self> {
142 debug_assert_eq!(element.name(), Self::NAME);
143 let mut it = element.children().peekable();
144 Ok(AnimationClip {
145 id: element.attr("id").map(Into::into),
146 name: element.attr("name").map(Into::into),
147 start: parse_attr(element.attr("start"))?.unwrap_or(0.),
148 end: parse_attr(element.attr("end"))?,
149 asset: Asset::parse_opt_box(&mut it)?,
150 instance_animation: Instance::parse_list_n::<1>(&mut it)?,
151 extra: Extra::parse_many(it)?,
152 })
153 }
154}
155
156impl XNodeWrite for AnimationClip {
157 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
158 let mut e = Self::elem();
159 e.opt_attr("id", &self.id);
160 e.opt_attr("name", &self.name);
161 e.print_attr("start", self.start);
162 e.opt_print_attr("end", &self.end);
163 let e = e.start(w)?;
164 self.asset.write_to(w)?;
165 self.instance_animation.write_to(w)?;
166 self.extra.write_to(w)?;
167 e.end(w)
168 }
169}
170
171#[derive(Clone, Debug)]
173pub struct Channel {
174 pub source: UrlRef<Sampler>,
176 pub target: Address,
178}
179
180impl Channel {
181 pub fn new(source: Url, target: String) -> Self {
183 Self {
184 source: Ref::new(source),
185 target: Address(target),
186 }
187 }
188}
189
190impl XNode for Channel {
191 const NAME: &'static str = "channel";
192 fn parse(element: &Element) -> Result<Self> {
193 debug_assert_eq!(element.name(), Self::NAME);
194 let target = element.attr("target").ok_or("expecting target attr")?;
195 Ok(Channel {
196 source: parse_attr(element.attr("source"))?.ok_or("missing source attr")?,
197 target: Address(target.into()),
198 })
199 }
200}
201
202impl XNodeWrite for Channel {
203 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
204 let mut e = Self::elem();
205 e.print_attr("source", &self.source);
206 e.print_attr("target", &self.target);
207 e.end(w)
208 }
209}
210
211#[derive(Clone, Debug)]
213pub struct Sampler {
214 pub id: Option<String>,
216 pub inputs: Vec<Input>,
218 pub interpolation: usize,
220}
221
222impl Sampler {
223 pub fn new(inputs: Vec<Input>) -> Self {
226 Self {
227 id: None,
228 interpolation: inputs
229 .iter()
230 .position(|i| i.semantic == Semantic::Interpolation)
231 .expect("sampler: missing INTERPOLATION input"),
232 inputs,
233 }
234 }
235}
236
237impl XNode for Sampler {
238 const NAME: &'static str = "sampler";
239 fn parse(element: &Element) -> Result<Self> {
240 debug_assert_eq!(element.name(), Self::NAME);
241 let mut it = element.children().peekable();
242 let inputs = Input::parse_list(&mut it)?;
243 let res = Sampler {
244 id: element.attr("id").map(Into::into),
245 interpolation: inputs
246 .iter()
247 .position(|i| i.semantic == Semantic::Interpolation)
248 .ok_or("sampler: missing INTERPOLATION input")?,
249 inputs,
250 };
251 finish(res, it)
252 }
253}
254
255impl XNodeWrite for Sampler {
256 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
257 let mut e = Self::elem();
258 e.opt_attr("id", &self.id);
259 let e = e.start(w)?;
260 self.inputs.write_to(w)?;
261 e.end(w)
262 }
263}
264
265impl CollectLocalMaps for Sampler {
266 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
267 maps.insert(self)
268 }
269}
270
271impl Traversable for Sampler {
272 fn traverse<'a, E>(
273 doc: &'a Document,
274 mut f: impl FnMut(&'a Self) -> Result<(), E>,
275 ) -> Result<(), E>
276 where
277 Self: 'a,
278 {
279 doc.iter()
280 .try_for_each(|lib: &Animation| lib.sampler.iter().try_for_each(&mut f))
281 }
282}
283
284impl Sampler {
285 pub fn interpolation_input(&self) -> &Input {
287 &self.inputs[self.interpolation]
288 }
289}