mesh_loader/collada/
material.rs

1use super::*;
2
3/// The `<library_materials>` element.
4///
5/// See the [specification][1.4] for details.
6///
7/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=279
8#[derive(Default)]
9pub(super) struct LibraryMaterials<'a> {
10    // /// The unique identifier of this element.
11    // pub(super) id: Option<&'a str>,
12    // /// The name of this element.
13    // pub(super) name: Option<&'a str>,
14    pub(super) materials: HashMap<&'a str, Material<'a>>,
15}
16
17/// The `<material>` element.
18///
19/// See the [specification][1.4] for details.
20///
21/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=280
22pub(super) struct Material<'a> {
23    /// The unique identifier of this element.
24    pub(super) id: &'a str,
25    /// The name of this element.
26    pub(super) name: Option<&'a str>,
27    pub(super) instance_effect: InstanceEffect<'a>,
28}
29
30/// The `<instance_effect>` element.
31///
32/// See the [specification][1.4] for details.
33///
34/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=271
35pub(super) struct InstanceEffect<'a> {
36    // /// The scoped identifier of this element.
37    // pub(super) sid: Option<&'a str>,
38    // /// The name of this element.
39    // pub(super) name: Option<&'a str>,
40    /// The URI of the location of the [`Effect`] to instantiate.
41    pub(super) url: Uri<'a, Effect<'a>>,
42}
43
44// -----------------------------------------------------------------------------
45// Parsing
46
47pub(super) fn parse_library_materials<'a>(
48    cx: &mut Context<'a>,
49    node: xml::Node<'a, '_>,
50) -> io::Result<()> {
51    debug_assert_eq!(node.tag_name().name(), "library_materials");
52    // cx.library_materials.id = node.attribute("id");
53    // cx.library_materials.name = node.attribute("name");
54
55    for node in node.element_children() {
56        match node.tag_name().name() {
57            "material" => {
58                let material = parse_material(node)?;
59                cx.library_materials.materials.insert(material.id, material);
60            }
61            "asset" | "extra" => { /* skip */ }
62            _ => return Err(error::unexpected_child_elem(node)),
63        }
64    }
65
66    // The specification says <library_materials> has 1 or more <material> elements,
67    // but some exporters write empty <library_materials/> tags.
68
69    Ok(())
70}
71
72fn parse_material<'a>(node: xml::Node<'a, '_>) -> io::Result<Material<'a>> {
73    debug_assert_eq!(node.tag_name().name(), "material");
74    // The specification say it is optional, but it is actually required.
75    let id = node.required_attribute("id")?;
76    let mut instance_effect = None;
77
78    for node in node.element_children() {
79        match node.tag_name().name() {
80            "instance_effect" => {
81                instance_effect = Some(parse_instance_effect(node)?);
82            }
83            "asset" | "extra" => { /* skip */ }
84            _ => return Err(error::unexpected_child_elem(node)),
85        }
86    }
87
88    let instance_effect = match instance_effect {
89        Some(instance_effect) => instance_effect,
90        None => return Err(error::one_or_more_elems(node, "instance_effect")),
91    };
92
93    Ok(Material {
94        id,
95        name: node.attribute("name"),
96        instance_effect,
97    })
98}
99
100fn parse_instance_effect<'a>(node: xml::Node<'a, '_>) -> io::Result<InstanceEffect<'a>> {
101    debug_assert_eq!(node.tag_name().name(), "instance_effect");
102    let url = node.parse_url("url")?;
103    Ok(InstanceEffect {
104        // sid: node.attribute("sid"),
105        // name: node.attribute("name"),
106        url,
107    })
108}