mesh_loader/collada/image.rs
1use super::*;
2
3/// The `<library_images>` element.
4///
5/// See the specifications ([1.4], [1.5]) for details.
6///
7/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=278
8/// [1.5]: https://www.khronos.org/files/collada_spec_1_5.pdf#page=327
9#[derive(Default)]
10pub(super) struct LibraryImages<'a> {
11 // /// The unique identifier of this element.
12 // pub(super) id: Option<&'a str>,
13 // /// The name of this element.
14 // pub(super) name: Option<&'a str>,
15 pub(super) images: HashMap<&'a str, Image<'a>>,
16}
17
18/// The `<image>` element.
19///
20/// See the specifications ([1.4], [1.5]) for details.
21///
22/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=268
23/// [1.5]: https://www.khronos.org/files/collada_spec_1_5.pdf#page=310
24pub(super) struct Image<'a> {
25 /// The unique identifier of this element.
26 pub(super) id: &'a str,
27 // /// The name of this element.
28 // pub(super) name: Option<&'a str>,
29 // /// The image format.
30 // pub(super) format: Option<&'a str>,
31 // /// The height of the image in pixels.
32 // pub(super) height: Option<u32>,
33 // /// The width of the image in pixels.
34 // pub(super) width: Option<u32>,
35 // /// The depth of the image in pixels. A 2-D image has a depth of 1, which is the default.
36 // pub(super) depth: u32,
37 /// An embedded image data or an external image file.
38 pub(super) source: ImageSource<'a>,
39}
40
41/// An embedded image data or an external image file.
42pub(super) enum ImageSource<'a> {
43 /// An embedded image data.
44 Data(Vec<u8>),
45 /// An external image file.
46 InitFrom(&'a str),
47 Skip,
48}
49
50// -----------------------------------------------------------------------------
51// Parsing
52
53pub(super) fn parse_library_images<'a>(
54 cx: &mut Context<'a>,
55 node: xml::Node<'a, '_>,
56) -> io::Result<()> {
57 debug_assert_eq!(node.tag_name().name(), "library_images");
58 // cx.library_images.id = node.attribute("id");
59 // cx.library_images.name = node.attribute("name");
60
61 for node in node.element_children() {
62 match node.tag_name().name() {
63 "image" => {
64 let image = parse_image(cx, node)?;
65 cx.library_images.images.insert(image.id, image);
66 }
67 "asset" | "extra" => { /* skip */ }
68 _ => return Err(error::unexpected_child_elem(node)),
69 }
70 }
71
72 // The specification says <library_images> has 1 or more <image> elements,
73 // but some exporters write empty <library_images/> tags.
74
75 Ok(())
76}
77
78fn parse_image<'a>(cx: &Context<'a>, node: xml::Node<'a, '_>) -> io::Result<Image<'a>> {
79 debug_assert_eq!(node.tag_name().name(), "image");
80 let id = node.required_attribute("id")?;
81 // let name = node.attribute("name");
82 let is_1_4 = cx.version.is_1_4();
83 if is_1_4 {
84 // let mut format = node.attribute("format");
85 let _height: Option<u32> = node.parse_attribute("height")?;
86 let _width: Option<u32> = node.parse_attribute("width")?;
87 let _depth: u32 = node.parse_attribute("depth")?.unwrap_or(1);
88 } else {
89 // let sid = node.attribute("sid");
90 }
91 let mut source = None;
92
93 for node in node.element_children() {
94 let tag_name = node.tag_name().name();
95 match tag_name {
96 "init_from" => {
97 if is_1_4 {
98 source = Some(ImageSource::InitFrom(node.trimmed_text()));
99 continue;
100 }
101 for node in node.element_children() {
102 match node.tag_name().name() {
103 "ref" => {
104 source = Some(ImageSource::InitFrom(node.trimmed_text()));
105 }
106 "hex" => {
107 // format = node.attribute("format");
108 let data = hex::decode(node.trimmed_text().as_bytes())?;
109 source = Some(ImageSource::Data(data));
110 }
111 _ => {}
112 }
113 }
114 }
115 "data" if is_1_4 => {
116 let data = hex::decode(node.trimmed_text().as_bytes())?;
117 source = Some(ImageSource::Data(data));
118 }
119 "asset" | "extra" => { /* skip */ }
120 _ if is_1_4 => return Err(error::unexpected_child_elem(node)),
121 _ => {}
122 }
123 }
124
125 let source = match source {
126 Some(source) => source,
127 None => {
128 if is_1_4 {
129 bail!(
130 "<{}> element must be contain <data> or <init_from> element ({})",
131 node.tag_name().name(),
132 node.node_location()
133 )
134 }
135 // 1.5 has <create_*> elements, but many applications ignore them.
136 ImageSource::Skip
137 }
138 };
139
140 Ok(Image {
141 id,
142 // name,
143 // format,
144 // height,
145 // width,
146 // depth,
147 source,
148 })
149}