dae_parser/core/
mod.rs

1mod anim;
2mod camera;
3mod control;
4mod data;
5mod ext;
6mod geom;
7mod light;
8mod meta;
9mod scene;
10mod transform;
11
12use crate::*;
13pub use {
14    anim::*, camera::*, control::*, data::*, ext::*, geom::*, light::*, meta::*, scene::*,
15    transform::*,
16};
17
18/// An unparsed COLLADA target address.
19/// See the "Address Syntax" section in Chapter 3: Schema concepts of the
20/// [COLLADA spec](https://www.khronos.org/files/collada_spec_1_4.pdf).
21#[derive(Clone, Debug)]
22pub struct Address(pub String);
23
24impl Display for Address {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        Display::fmt(&self.0, f)
27    }
28}
29
30/// A trait for nodes that can be placed in a library element.
31pub trait ParseLibrary: XNode {
32    /// The name of the library element. For example, the [`Geometry`] element has
33    /// `LIBRARY = "library_geometries"`,
34    /// and the corresponding library type is [`Library`]`<Geometry>`.
35    const LIBRARY: &'static str;
36
37    /// Extract the library from a single [`LibraryElement`].
38    fn extract_element(e: &LibraryElement) -> Option<&Library<Self>>;
39
40    /// Make a [`LibraryElement`] from a [`Library`].
41    fn mk_element(lib: Library<Self>) -> LibraryElement;
42}
43
44/// Declares a module of elements of type `T`.
45#[derive(Clone, Debug)]
46pub struct Library<T> {
47    /// Asset management information about this element.
48    pub asset: Option<Box<Asset>>,
49    /// The individual items in the module.
50    pub items: Vec<T>,
51    /// Provides arbitrary additional information about this element.
52    pub extra: Vec<Extra>,
53}
54
55impl<T> Library<T> {
56    /// Construct a new `Library` with the given elements.
57    pub fn new(items: Vec<T>) -> Self {
58        Self {
59            asset: None,
60            items,
61            extra: vec![],
62        }
63    }
64
65    /// Does this element have no children?
66    pub fn is_empty(&self) -> bool {
67        self.asset.is_none() && self.items.is_empty() && self.extra.is_empty()
68    }
69}
70
71impl<T> From<Vec<T>> for Library<T> {
72    fn from(items: Vec<T>) -> Self {
73        Self::new(items)
74    }
75}
76
77impl<T: ParseLibrary> XNode for Library<T> {
78    const NAME: &'static str = T::LIBRARY;
79    fn parse(element: &Element) -> Result<Self> {
80        debug_assert_eq!(element.name(), Self::NAME);
81        let mut it = element.children().peekable();
82        Ok(Library {
83            asset: Asset::parse_opt_box(&mut it)?,
84            items: T::parse_list(&mut it)?, // should be 1 or more but blender disagrees
85            extra: Extra::parse_many(it)?,
86        })
87    }
88}
89
90impl<T: ParseLibrary> XNodeWrite for Library<T> {
91    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
92        let e = Self::elem();
93        if self.is_empty() {
94            e.end(w)
95        } else {
96            let e = e.start(w)?;
97            self.asset.write_to(w)?;
98            self.items.write_to(w)?;
99            self.extra.write_to(w)?;
100            e.end(w)
101        }
102    }
103}
104
105impl<T: CollectLocalMaps> CollectLocalMaps for Library<T> {
106    fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
107        self.items.collect_local_maps(maps)
108    }
109}
110
111macro_rules! mk_libraries {
112    (@mkdoc $($doc:expr, $name:ident, $arg:ident,)*) => {
113        /// A library element, which can be a module of any of the kinds supported by COLLADA.
114        #[derive(Clone, Debug)]
115        pub enum LibraryElement {
116            $(#[doc = $doc] $name(Library<$arg>),)*
117        }
118    };
119    ($($(#[derive(Traversable $(, CollectLocalMaps $($mark:literal)?)?)])?
120        $name:ident($arg:ident) = $s:literal,
121    )*) => {
122        $(
123            $(
124                impl Traversable for $arg {
125                    fn traverse<'a, E>(
126                        doc: &'a Document,
127                        f: impl FnMut(&'a $arg) -> Result<(), E>,
128                    ) -> Result<(), E> {
129                        doc.iter().try_for_each(f)
130                    }
131                }
132
133                $(impl CollectLocalMaps $($mark)? for $arg {
134                    fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
135                        maps.insert(self)
136                    }
137                })?
138            )?
139
140            impl ParseLibrary for $arg {
141                const LIBRARY: &'static str = $s;
142
143                fn extract_element(e: &LibraryElement) -> Option<&Library<Self>> {
144                    if let LibraryElement::$name(arg) = e {
145                        Some(arg)
146                    } else {
147                        None
148                    }
149                }
150
151                fn mk_element(lib: Library<Self>) -> LibraryElement {
152                    LibraryElement::$name(lib)
153                }
154            }
155        )*
156
157        mk_libraries! {
158            @mkdoc $(
159                concat!("Declares a module of [`", stringify!($arg), "`] elements."),
160                $name, $arg,
161            )*
162        }
163
164        impl LibraryElement {
165            /// Parse a [`LibraryElement`] from an XML element.
166            pub fn parse(e: &Element) -> Result<Option<Self>> {
167                Ok(Some(match e.name() {
168                    $($arg::LIBRARY => Self::$name(Library::parse(e)?),)*
169                    _ => return Ok(None),
170                }))
171            }
172        }
173
174        impl XNodeWrite for LibraryElement {
175            fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
176                match self {
177                    $(Self::$name(lib) => lib.write_to(w),)*
178                }
179            }
180        }
181
182        impl CollectLocalMaps for LibraryElement {
183            fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
184                match self {
185                    $(Self::$name(lib) => lib.collect_local_maps(maps),)*
186                }
187            }
188        }
189    }
190}
191
192mk_libraries! {
193    Animations(Animation) = "library_animations",
194
195    #[derive(Traversable, CollectLocalMaps)]
196    AnimationClips(AnimationClip) = "library_animation_clips",
197
198    #[derive(Traversable, CollectLocalMaps)]
199    Cameras(Camera) = "library_cameras",
200
201    #[derive(Traversable, CollectLocalMaps)]
202    Controllers(Controller) = "library_controllers",
203
204    #[derive(Traversable, CollectLocalMaps)]
205    Effects(Effect) = "library_effects",
206
207    #[derive(Traversable, CollectLocalMaps)]
208    ForceFields(ForceField) = "library_force_fields",
209
210    #[derive(Traversable)]
211    Geometries(Geometry) = "library_geometries",
212
213    #[derive(Traversable, CollectLocalMaps)]
214    Images(Image) = "library_images",
215
216    #[derive(Traversable, CollectLocalMaps)]
217    Lights(Light) = "library_lights",
218
219    #[derive(Traversable, CollectLocalMaps)]
220    Materials(Material) = "library_materials",
221
222    Nodes(Node) = "library_nodes",
223
224    #[derive(Traversable, CollectLocalMaps)]
225    PhysicsMaterials(PhysicsMaterial) = "library_physics_materials",
226
227    #[derive(Traversable, CollectLocalMaps)]
228    PhysicsModels(PhysicsModel) = "library_physics_models",
229
230    #[derive(Traversable, CollectLocalMaps)]
231    PhysicsScenes(PhysicsScene) = "library_physics_scenes",
232
233    #[derive(Traversable, CollectLocalMaps)]
234    VisualScenes(VisualScene) = "library_visual_scenes",
235}
236
237/// Instantiates a COLLADA material resource,
238/// possibly applying transformations or effects to the object.
239///
240/// The `data` field depends on the type of object being instantiated.
241/// Most types use `()` for this field but some types have additional data:
242/// * `Instance<`[`Geometry`]>: [`InstanceGeometryData`]
243/// * `Instance<`[`Controller`]>: [`InstanceControllerData`]
244/// * `Instance<`[`Effect`]>: [`InstanceEffectData`]
245/// * `Instance<`[`PhysicsModel`]>: [`InstancePhysicsModelData`]
246///
247/// Additionally, some instance nodes are even more different and have their own types:
248/// * [`InstanceMaterial`], not `Instance<`[`Material`]`>`
249/// * [`InstanceRigidBody`], not `Instance<`[`RigidBody`]`>`
250/// * [`InstanceRigidConstraint`], not `Instance<`[`RigidConstraint`]`>`
251#[derive(Clone, Debug)]
252pub struct Instance<T: Instantiate> {
253    /// A text string containing the scoped identifier of this element.
254    /// This value must be unique within the scope of the parent element.
255    pub sid: Option<String>,
256    /// The URL of the location of the `T` element to instantiate.
257    /// Can refer to a local instance or external reference.
258    pub url: UrlRef<T>,
259    /// The text string name of this element.
260    pub name: Option<String>,
261    /// The additional data associated with the instantiation, if any.
262    pub data: T::Data,
263    /// Provides arbitrary additional information about this element.
264    pub extra: Vec<Extra>,
265}
266
267pub(crate) use private::Instantiate;
268pub(crate) mod private {
269    use super::*;
270    /// The trait for types that can be used in [`Instance<T>`].
271    pub trait Instantiate {
272        /// The name of the instance node.
273        /// For example `Geometry::INSTANCE = "instance_geometry"`.
274        const INSTANCE: &'static str;
275
276        /// The type of additional data associated with instantiations, possibly `()`.
277        type Data: XNodeWrite + Default;
278
279        /// Parse the [`Self::Data`] given an element iterator,
280        /// and a reference to the parent element.
281        fn parse_data(e: &Element, it: &mut ElementIter<'_>) -> Result<Self::Data>;
282
283        /// Write attributes from the [`Self::Data`], before the main write.
284        fn write_attr(_: &Self::Data, _: &mut ElemBuilder) {}
285
286        /// Returns true if the data field has no elements.
287        fn is_empty(_: &Self::Data) -> bool;
288    }
289}
290
291impl<T: Instantiate> Instance<T> {
292    /// Construct a new instance pointing at the given [`Url`] (which should
293    /// reference an object of type `T`).
294    pub fn new(url: Url) -> Self {
295        Self {
296            sid: Default::default(),
297            url: Ref::new(url),
298            name: Default::default(),
299            data: Default::default(),
300            extra: Default::default(),
301        }
302    }
303}
304
305impl<T: Instantiate> XNode for Instance<T> {
306    const NAME: &'static str = T::INSTANCE;
307    fn parse(element: &Element) -> Result<Self> {
308        debug_assert_eq!(element.name(), Self::NAME);
309        let mut it = element.children().peekable();
310        Ok(Instance {
311            sid: element.attr("sid").map(Into::into),
312            url: parse_attr(element.attr("url"))?.ok_or("missing url attribute")?,
313            name: element.attr("name").map(Into::into),
314            data: T::parse_data(element, &mut it)?,
315            extra: Extra::parse_many(it)?,
316        })
317    }
318}
319
320impl<T: Instantiate> XNodeWrite for Instance<T> {
321    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
322        let mut e = Self::elem();
323        e.opt_attr("sid", &self.sid);
324        e.print_attr("url", &self.url);
325        e.opt_attr("name", &self.name);
326        T::write_attr(&self.data, &mut e);
327        if T::is_empty(&self.data) && self.extra.is_empty() {
328            e.end(w)
329        } else {
330            let e = e.start(w)?;
331            self.data.write_to(w)?;
332            self.extra.write_to(w)?;
333            e.end(w)
334        }
335    }
336}
337
338impl<T: Instantiate> CollectLocalMaps for Instance<T>
339where
340    T::Data: CollectLocalMaps,
341{
342    fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
343        self.data.collect_local_maps(maps);
344    }
345}
346
347/// Either an instance of a `T`, or a directly inlined `T` object.
348pub enum DefInstance<T: Instantiate> {
349    /// A definition of a `T`.
350    Def(T),
351    /// An instantiation of a `T`.
352    Ref(Instance<T>),
353}
354
355impl<T: Instantiate> From<Instance<T>> for DefInstance<T> {
356    fn from(v: Instance<T>) -> Self {
357        Self::Ref(v)
358    }
359}
360
361impl<T: Instantiate> From<T> for DefInstance<T> {
362    fn from(v: T) -> Self {
363        Self::Def(v)
364    }
365}
366
367impl<T: Instantiate + Debug> Debug for DefInstance<T>
368where
369    T::Data: Debug,
370{
371    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372        match self {
373            Self::Def(t) => f.debug_tuple("Def").field(t).finish(),
374            Self::Ref(t) => f.debug_tuple("Ref").field(t).finish(),
375        }
376    }
377}
378
379impl<T: Instantiate + Clone> Clone for DefInstance<T>
380where
381    T::Data: Clone,
382{
383    fn clone(&self) -> Self {
384        match self {
385            Self::Def(t) => Self::Def(t.clone()),
386            Self::Ref(t) => Self::Ref(t.clone()),
387        }
388    }
389}
390
391impl<T: Instantiate + XNode> DefInstance<T> {
392    pub(crate) fn parse(e: &Element) -> Result<Option<Self>> {
393        Ok(if e.name() == T::NAME {
394            Some(Self::Def(T::parse(e)?))
395        } else if e.name() == T::INSTANCE {
396            Some(Self::Ref(Instance::parse(e)?))
397        } else {
398            None
399        })
400    }
401}
402
403impl<T: Instantiate + XNodeWrite> XNodeWrite for DefInstance<T> {
404    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
405        match self {
406            DefInstance::Def(e) => e.write_to(w),
407            DefInstance::Ref(e) => e.write_to(w),
408        }
409    }
410}
411
412impl<T: Instantiate + CollectLocalMaps> CollectLocalMaps for DefInstance<T> {
413    fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
414        if let DefInstance::Def(t) = self {
415            t.collect_local_maps(maps);
416        }
417    }
418}
419
420macro_rules! basic_instance {
421    ($($ty:ty => $val:expr;)*) => {
422        $(impl Instantiate for $ty {
423            const INSTANCE: &'static str = $val;
424            type Data = ();
425            fn parse_data(_: &Element, _: &mut ElementIter<'_>) -> Result<Self::Data> {
426                Ok(())
427            }
428            fn is_empty(_: &Self::Data) -> bool { true }
429        })*
430    }
431}
432basic_instance! {
433    Animation => "instance_animation";
434    Camera => "instance_camera";
435    ForceField => "instance_force_field";
436    Light => "instance_light";
437    Node => "instance_node";
438    PhysicsMaterial => "instance_physics_material";
439    PhysicsScene => "instance_physics_scene";
440    VisualScene => "instance_visual_scene";
441}