mesh_loader/collada/image.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 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
use super::*;
/// The `<library_images>` element.
///
/// See the specifications ([1.4], [1.5]) for details.
///
/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=278
/// [1.5]: https://www.khronos.org/files/collada_spec_1_5.pdf#page=327
#[derive(Default)]
pub(super) struct LibraryImages<'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) images: HashMap<&'a str, Image<'a>>,
}
/// The `<image>` element.
///
/// See the specifications ([1.4], [1.5]) for details.
///
/// [1.4]: https://www.khronos.org/files/collada_spec_1_4.pdf#page=268
/// [1.5]: https://www.khronos.org/files/collada_spec_1_5.pdf#page=310
pub(super) struct Image<'a> {
/// The unique identifier of this element.
pub(super) id: &'a str,
// /// The name of this element.
// pub(super) name: Option<&'a str>,
// /// The image format.
// pub(super) format: Option<&'a str>,
// /// The height of the image in pixels.
// pub(super) height: Option<u32>,
// /// The width of the image in pixels.
// pub(super) width: Option<u32>,
// /// The depth of the image in pixels. A 2-D image has a depth of 1, which is the default.
// pub(super) depth: u32,
/// An embedded image data or an external image file.
pub(super) source: ImageSource<'a>,
}
/// An embedded image data or an external image file.
pub(super) enum ImageSource<'a> {
/// An embedded image data.
Data(Vec<u8>),
/// An external image file.
InitFrom(&'a str),
Skip,
}
// -----------------------------------------------------------------------------
// Parsing
pub(super) fn parse_library_images<'a>(
cx: &mut Context<'a>,
node: xml::Node<'a, '_>,
) -> io::Result<()> {
debug_assert_eq!(node.tag_name().name(), "library_images");
// cx.library_images.id = node.attribute("id");
// cx.library_images.name = node.attribute("name");
for node in node.element_children() {
match node.tag_name().name() {
"image" => {
let image = parse_image(cx, node)?;
cx.library_images.images.insert(image.id, image);
}
"asset" | "extra" => { /* skip */ }
_ => return Err(error::unexpected_child_elem(node)),
}
}
// The specification says <library_images> has 1 or more <image> elements,
// but some exporters write empty <library_images/> tags.
Ok(())
}
fn parse_image<'a>(cx: &Context<'a>, node: xml::Node<'a, '_>) -> io::Result<Image<'a>> {
debug_assert_eq!(node.tag_name().name(), "image");
let id = node.required_attribute("id")?;
// let name = node.attribute("name");
let is_1_4 = cx.version.is_1_4();
if is_1_4 {
// let mut format = node.attribute("format");
let _height: Option<u32> = node.parse_attribute("height")?;
let _width: Option<u32> = node.parse_attribute("width")?;
let _depth: u32 = node.parse_attribute("depth")?.unwrap_or(1);
} else {
// let sid = node.attribute("sid");
}
let mut source = None;
for node in node.element_children() {
let tag_name = node.tag_name().name();
match tag_name {
"init_from" => {
if is_1_4 {
source = Some(ImageSource::InitFrom(node.trimmed_text()));
continue;
}
for node in node.element_children() {
match node.tag_name().name() {
"ref" => {
source = Some(ImageSource::InitFrom(node.trimmed_text()));
}
"hex" => {
// format = node.attribute("format");
let data = hex::decode(node.trimmed_text().as_bytes())?;
source = Some(ImageSource::Data(data));
}
_ => {}
}
}
}
"data" if is_1_4 => {
let data = hex::decode(node.trimmed_text().as_bytes())?;
source = Some(ImageSource::Data(data));
}
"asset" | "extra" => { /* skip */ }
_ if is_1_4 => return Err(error::unexpected_child_elem(node)),
_ => {}
}
}
let source = match source {
Some(source) => source,
None => {
if is_1_4 {
bail!(
"<{}> element must be contain <data> or <init_from> element ({})",
node.tag_name().name(),
node.node_location()
)
}
// 1.5 has <create_*> elements, but many applications ignore them.
ImageSource::Skip
}
};
Ok(Image {
id,
// name,
// format,
// height,
// width,
// depth,
source,
})
}