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