lib3mf_core/parser/
material_parser.rs1use crate::error::{Lib3mfError, Result};
2use crate::model::{
3 BaseMaterial, BaseMaterialsGroup, BlendMethod, Color, ColorGroup, Composite,
4 CompositeMaterials, Multi, MultiProperties, ResourceId, Texture2DCoord, Texture2DGroup,
5};
6use crate::parser::xml_parser::{XmlParser, get_attribute};
7use quick_xml::events::Event;
8use std::io::BufRead;
9
10pub fn parse_texture_2d_group<R: BufRead>(
14 parser: &mut XmlParser<R>,
15 id: ResourceId,
16 texture_id: ResourceId,
17) -> Result<Texture2DGroup> {
18 let mut coords = Vec::new();
19
20 loop {
21 match parser.read_next_event()? {
22 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"tex2coord" => {
23 let u = get_attribute(&e, b"u")
24 .ok_or_else(|| Lib3mfError::Validation("tex2coord missing u".to_string()))?
25 .parse::<f32>()
26 .map_err(|_| Lib3mfError::Validation("Invalid u value".to_string()))?;
27 let v = get_attribute(&e, b"v")
28 .ok_or_else(|| Lib3mfError::Validation("tex2coord missing v".to_string()))?
29 .parse::<f32>()
30 .map_err(|_| Lib3mfError::Validation("Invalid v value".to_string()))?;
31 coords.push(Texture2DCoord { u, v });
32 }
33 Event::End(e) if e.local_name().as_ref() == b"texture2dgroup" => break,
34 Event::Eof => {
35 return Err(Lib3mfError::Validation(
36 "Unexpected EOF in texture2dgroup".to_string(),
37 ));
38 }
39 _ => {}
40 }
41 }
42
43 Ok(Texture2DGroup {
44 id,
45 texture_id,
46 coords,
47 })
48}
49
50pub fn parse_composite_materials<R: BufRead>(
52 parser: &mut XmlParser<R>,
53 id: ResourceId,
54 base_material_id: ResourceId,
55 indices: Vec<u32>,
56) -> Result<CompositeMaterials> {
57 let mut composites = Vec::new();
58
59 loop {
60 match parser.read_next_event()? {
61 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"composite" => {
62 let values_str = get_attribute(&e, b"values").ok_or_else(|| {
63 Lib3mfError::Validation("composite missing values".to_string())
64 })?;
65 let values = values_str
66 .split_whitespace()
67 .map(|s| {
68 s.parse::<f32>().map_err(|_| {
69 Lib3mfError::Validation("Invalid composite value".to_string())
70 })
71 })
72 .collect::<Result<Vec<f32>>>()?;
73 composites.push(Composite { values });
74 }
75 Event::End(e) if e.local_name().as_ref() == b"compositematerials" => break,
76 Event::Eof => {
77 return Err(Lib3mfError::Validation(
78 "Unexpected EOF in compositematerials".to_string(),
79 ));
80 }
81 _ => {}
82 }
83 }
84
85 Ok(CompositeMaterials {
86 id,
87 base_material_id,
88 indices,
89 composites,
90 })
91}
92
93pub fn parse_multi_properties<R: BufRead>(
95 parser: &mut XmlParser<R>,
96 id: ResourceId,
97 pids: Vec<ResourceId>,
98 blend_methods: Vec<BlendMethod>,
99) -> Result<MultiProperties> {
100 let mut multis = Vec::new();
101
102 loop {
103 match parser.read_next_event()? {
104 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"multi" => {
105 let pindices_str = get_attribute(&e, b"pindices")
106 .ok_or_else(|| Lib3mfError::Validation("multi missing pindices".to_string()))?;
107 let pindices = pindices_str
108 .split_whitespace()
109 .map(|s| {
110 s.parse::<u32>().map_err(|_| {
111 Lib3mfError::Validation("Invalid pindex value".to_string())
112 })
113 })
114 .collect::<Result<Vec<u32>>>()?;
115 multis.push(Multi { pindices });
116 }
117 Event::End(e) if e.local_name().as_ref() == b"multiproperties" => break,
118 Event::Eof => {
119 return Err(Lib3mfError::Validation(
120 "Unexpected EOF in multiproperties".to_string(),
121 ));
122 }
123 _ => {}
124 }
125 }
126
127 Ok(MultiProperties {
128 id,
129 pids,
130 blend_methods,
131 multis,
132 })
133}
134
135pub fn parse_base_materials<R: BufRead>(
137 parser: &mut XmlParser<R>,
138 id: ResourceId,
139) -> Result<BaseMaterialsGroup> {
140 let mut materials = Vec::new();
141
142 loop {
143 match parser.read_next_event()? {
144 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"base" => {
145 let name = get_attribute(&e, b"name").ok_or_else(|| {
146 Lib3mfError::Validation("base element missing 'name' attribute".to_string())
147 })?;
148 let color_hex = get_attribute(&e, b"displaycolor").ok_or_else(|| {
149 Lib3mfError::Validation(
150 "base element missing 'displaycolor' attribute".to_string(),
151 )
152 })?;
153 let display_color = Color::from_hex(&color_hex).ok_or_else(|| {
154 Lib3mfError::Validation(format!("Invalid color format: {}", color_hex))
155 })?;
156
157 materials.push(BaseMaterial {
158 name: name.into_owned(),
159 display_color,
160 });
161 }
162 Event::End(e) if e.local_name().as_ref() == b"basematerials" => break,
163 Event::Eof => {
164 return Err(Lib3mfError::Validation(
165 "Unexpected EOF in basematerials".to_string(),
166 ));
167 }
168 _ => {}
169 }
170 }
171
172 Ok(BaseMaterialsGroup { id, materials })
173}
174
175pub fn parse_color_group<R: BufRead>(
177 parser: &mut XmlParser<R>,
178 id: ResourceId,
179) -> Result<ColorGroup> {
180 let mut colors = Vec::new();
181
182 loop {
183 match parser.read_next_event()? {
184 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"color" => {
185 let color_hex = get_attribute(&e, b"color").ok_or_else(|| {
186 Lib3mfError::Validation("color element missing 'color' attribute".to_string())
187 })?;
188 let color = Color::from_hex(&color_hex).ok_or_else(|| {
189 Lib3mfError::Validation(format!("Invalid color format: {}", color_hex))
190 })?;
191 colors.push(color);
192 }
193 Event::End(e) if e.local_name().as_ref() == b"colorgroup" => break,
194 Event::Eof => {
195 return Err(Lib3mfError::Validation(
196 "Unexpected EOF in colorgroup".to_string(),
197 ));
198 }
199 _ => {}
200 }
201 }
202
203 Ok(ColorGroup { id, colors })
204}