1use crate::error::{Lib3mfError, Result};
2use crate::model::{Beam, BuildItem, CapMode, DisplacementTriangle, ResourceId};
3use crate::parser::material_parser::{parse_base_materials, parse_color_group};
4use crate::parser::visitor::ModelVisitor;
5use crate::parser::xml_parser::{XmlParser, get_attribute, get_attribute_f32, get_attribute_u32};
6use glam::Mat4;
7use quick_xml::events::Event;
8use std::io::BufRead;
9
10pub fn parse_model_streaming<R: BufRead, V: ModelVisitor>(
13 reader: R,
14 visitor: &mut V,
15) -> Result<()> {
16 let mut parser = XmlParser::new(reader);
17
18 visitor.on_start_model()?;
19
20 loop {
21 match parser.read_next_event()? {
22 Event::Start(e) => {
23 match e.name().as_ref() {
24 b"model" => {
25 }
27 b"metadata" => {
28 let name = get_attribute(&e, b"name")
29 .ok_or(Lib3mfError::Validation("Metadata missing name".to_string()))?
30 .into_owned();
31 let content = parser.read_text_content()?;
32 visitor.on_metadata(&name, &content)?;
33 }
34 b"resources" => {
35 visitor.on_start_resources()?;
36 parse_resources_streaming(&mut parser, visitor)?;
37 visitor.on_end_resources()?;
38 }
39 b"build" => {
40 visitor.on_start_build()?;
41 parse_build_streaming(&mut parser, visitor)?;
42 visitor.on_end_build()?;
43 }
44 _ => {}
45 }
46 }
47 Event::Empty(e) => {
48 if e.name().as_ref() == b"metadata" {
49 let name = get_attribute(&e, b"name")
50 .ok_or(Lib3mfError::Validation("Metadata missing name".to_string()))?;
51 visitor.on_metadata(name.as_ref(), "")?;
52 }
53 }
54 Event::End(e) if e.name().as_ref() == b"model" => break,
55 Event::Eof => break,
56 _ => {}
57 }
58 }
59
60 visitor.on_end_model()?;
61 Ok(())
62}
63
64fn parse_resources_streaming<R: BufRead, V: ModelVisitor>(
65 parser: &mut XmlParser<R>,
66 visitor: &mut V,
67) -> Result<()> {
68 loop {
69 match parser.read_next_event()? {
70 Event::Start(e) => {
71 let local_name = e.local_name();
72 match local_name.as_ref() {
73 b"object" => {
74 let id = ResourceId(get_attribute_u32(&e, b"id")?);
75 parse_object_content_streaming(parser, visitor, id)?;
76 }
77 b"basematerials" => {
78 let id = ResourceId(get_attribute_u32(&e, b"id")?);
79 let group = parse_base_materials(parser, id)?;
80 visitor.on_base_materials(id, &group)?;
81 }
82 b"colorgroup" => {
83 let id = ResourceId(get_attribute_u32(&e, b"id")?);
84 let group = parse_color_group(parser, id)?;
85 visitor.on_color_group(id, &group)?;
86 }
87 _ => {}
88 }
89 }
90 Event::End(e) if e.name().as_ref() == b"resources" => break,
91 Event::Eof => {
92 return Err(Lib3mfError::Validation(
93 "Unexpected EOF in resources".to_string(),
94 ));
95 }
96 _ => {}
97 }
98 }
99 Ok(())
100}
101
102fn parse_object_content_streaming<R: BufRead, V: ModelVisitor>(
103 parser: &mut XmlParser<R>,
104 visitor: &mut V,
105 object_id: ResourceId,
106) -> Result<()> {
107 loop {
108 match parser.read_next_event()? {
109 Event::Start(e) => match e.local_name().as_ref() {
110 b"mesh" => {
111 visitor.on_start_mesh(object_id)?;
112 parse_mesh_streaming(parser, visitor, object_id)?;
113 visitor.on_end_mesh()?;
114 }
115 b"components" => {
116 }
118 b"displacementmesh" => {
119 visitor.on_start_displacement_mesh(object_id)?;
120 parse_displacement_mesh_streaming(parser, visitor)?;
121 visitor.on_end_displacement_mesh()?;
122 }
123 _ => {}
124 },
125 Event::End(e) if e.local_name().as_ref() == b"object" => break,
126 Event::Eof => {
127 return Err(Lib3mfError::Validation(
128 "Unexpected EOF in object".to_string(),
129 ));
130 }
131 _ => {}
132 }
133 }
134 Ok(())
135}
136
137fn parse_mesh_streaming<R: BufRead, V: ModelVisitor>(
138 parser: &mut XmlParser<R>,
139 visitor: &mut V,
140 object_id: ResourceId,
141) -> Result<()> {
142 loop {
143 match parser.read_next_event()? {
144 Event::Start(e) => match e.local_name().as_ref() {
145 b"vertices" => parse_vertices_streaming(parser, visitor)?,
146 b"triangles" => parse_triangles_streaming(parser, visitor)?,
147 b"beamlattice" => {
148 let default_radius = get_attribute_f32(&e, b"radius").unwrap_or(0.0);
149 visitor.on_start_beam_lattice(object_id)?;
150 parse_beam_lattice_streaming(parser, visitor, default_radius)?;
151 visitor.on_end_beam_lattice()?;
152 }
153 _ => {}
154 },
155 Event::End(e) if e.local_name().as_ref() == b"mesh" => break,
156 Event::Eof => {
157 return Err(Lib3mfError::Validation(
158 "Unexpected EOF in mesh".to_string(),
159 ));
160 }
161 _ => {}
162 }
163 }
164 Ok(())
165}
166
167fn parse_vertices_streaming<R: BufRead, V: ModelVisitor>(
168 parser: &mut XmlParser<R>,
169 visitor: &mut V,
170) -> Result<()> {
171 loop {
172 match parser.read_next_event()? {
173 Event::Start(e) | Event::Empty(e) => {
174 if e.name().as_ref() == b"vertex" {
175 let x = get_attribute_f32(&e, b"x")?;
176 let y = get_attribute_f32(&e, b"y")?;
177 let z = get_attribute_f32(&e, b"z")?;
178 visitor.on_vertex(x, y, z)?;
179 }
180 }
181 Event::End(e) if e.name().as_ref() == b"vertices" => break,
182 Event::Eof => {
183 return Err(Lib3mfError::Validation(
184 "Unexpected EOF in vertices".to_string(),
185 ));
186 }
187 _ => {}
188 }
189 }
190 Ok(())
191}
192
193fn parse_triangles_streaming<R: BufRead, V: ModelVisitor>(
194 parser: &mut XmlParser<R>,
195 visitor: &mut V,
196) -> Result<()> {
197 loop {
198 match parser.read_next_event()? {
199 Event::Start(e) | Event::Empty(e) => {
200 if e.name().as_ref() == b"triangle" {
201 let v1 = get_attribute_u32(&e, b"v1")?;
202 let v2 = get_attribute_u32(&e, b"v2")?;
203 let v3 = get_attribute_u32(&e, b"v3")?;
204 visitor.on_triangle(v1, v2, v3)?;
205 }
206 }
207 Event::End(e) if e.name().as_ref() == b"triangles" => break,
208 Event::Eof => {
209 return Err(Lib3mfError::Validation(
210 "Unexpected EOF in triangles".to_string(),
211 ));
212 }
213 _ => {}
214 }
215 }
216 Ok(())
217}
218
219fn parse_beam_lattice_streaming<R: BufRead, V: ModelVisitor>(
220 parser: &mut XmlParser<R>,
221 visitor: &mut V,
222 default_radius: f32,
223) -> Result<()> {
224 loop {
225 match parser.read_next_event()? {
226 Event::Start(e) => match e.local_name().as_ref() {
227 b"beams" => parse_beams_streaming(parser, visitor, default_radius)?,
228 b"beamsets" => {
229 parser.read_to_end(b"beamsets")?;
232 }
233 _ => {}
234 },
235 Event::End(e) if e.local_name().as_ref() == b"beamlattice" => break,
236 Event::Eof => {
237 return Err(Lib3mfError::Validation(
238 "Unexpected EOF in beamlattice".to_string(),
239 ));
240 }
241 _ => {}
242 }
243 }
244 Ok(())
245}
246
247fn parse_beams_streaming<R: BufRead, V: ModelVisitor>(
248 parser: &mut XmlParser<R>,
249 visitor: &mut V,
250 default_radius: f32,
251) -> Result<()> {
252 loop {
253 match parser.read_next_event()? {
254 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"beam" => {
255 let v1 = get_attribute_u32(&e, b"v1")?;
256 let v2 = get_attribute_u32(&e, b"v2")?;
257 let r1 = get_attribute_f32(&e, b"r1").unwrap_or(default_radius);
258 let r2 = get_attribute_f32(&e, b"r2").unwrap_or(r1);
259 let p1 = get_attribute_u32(&e, b"p1").ok();
260 let p2 = get_attribute_u32(&e, b"p2").ok();
261 let cap_mode = if let Some(s) = get_attribute(&e, b"cap") {
262 match s.as_ref() {
263 "sphere" => CapMode::Sphere,
264 "hemisphere" => CapMode::Hemisphere,
265 "butt" => CapMode::Butt,
266 _ => CapMode::Sphere,
267 }
268 } else {
269 CapMode::Sphere
270 };
271 visitor.on_beam(&Beam {
272 v1,
273 v2,
274 r1,
275 r2,
276 p1,
277 p2,
278 cap_mode,
279 })?;
280 }
281 Event::End(e) if e.local_name().as_ref() == b"beams" => break,
282 Event::Eof => {
283 return Err(Lib3mfError::Validation(
284 "Unexpected EOF in beams".to_string(),
285 ));
286 }
287 _ => {}
288 }
289 }
290 Ok(())
291}
292
293fn parse_displacement_mesh_streaming<R: BufRead, V: ModelVisitor>(
294 parser: &mut XmlParser<R>,
295 visitor: &mut V,
296) -> Result<()> {
297 loop {
298 match parser.read_next_event()? {
299 Event::Start(e) => match e.local_name().as_ref() {
300 b"vertices" => parse_displacement_vertices_streaming(parser, visitor)?,
301 b"triangles" => parse_displacement_triangles_streaming(parser, visitor)?,
302 b"normvectors" => parse_displacement_normals_streaming(parser, visitor)?,
303 b"disp2dgroups" => {
304 parser.read_to_end(b"disp2dgroups")?;
308 }
309 _ => {}
310 },
311 Event::End(e) if e.local_name().as_ref() == b"displacementmesh" => break,
312 Event::Eof => {
313 return Err(Lib3mfError::Validation(
314 "Unexpected EOF in displacementmesh".to_string(),
315 ));
316 }
317 _ => {}
318 }
319 }
320 Ok(())
321}
322
323fn parse_displacement_vertices_streaming<R: BufRead, V: ModelVisitor>(
324 parser: &mut XmlParser<R>,
325 visitor: &mut V,
326) -> Result<()> {
327 loop {
328 match parser.read_next_event()? {
329 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"vertex" => {
330 let x = get_attribute_f32(&e, b"x")?;
331 let y = get_attribute_f32(&e, b"y")?;
332 let z = get_attribute_f32(&e, b"z")?;
333 visitor.on_displacement_vertex(x, y, z)?;
334 }
335 Event::End(e) if e.local_name().as_ref() == b"vertices" => break,
336 Event::Eof => {
337 return Err(Lib3mfError::Validation(
338 "Unexpected EOF in displacement vertices".to_string(),
339 ));
340 }
341 _ => {}
342 }
343 }
344 Ok(())
345}
346
347fn parse_displacement_triangles_streaming<R: BufRead, V: ModelVisitor>(
348 parser: &mut XmlParser<R>,
349 visitor: &mut V,
350) -> Result<()> {
351 loop {
352 match parser.read_next_event()? {
353 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"triangle" => {
354 let triangle = DisplacementTriangle {
355 v1: get_attribute_u32(&e, b"v1")?,
356 v2: get_attribute_u32(&e, b"v2")?,
357 v3: get_attribute_u32(&e, b"v3")?,
358 d1: get_attribute_u32(&e, b"d1").ok(),
359 d2: get_attribute_u32(&e, b"d2").ok(),
360 d3: get_attribute_u32(&e, b"d3").ok(),
361 p1: get_attribute_u32(&e, b"p1").ok(),
362 p2: get_attribute_u32(&e, b"p2").ok(),
363 p3: get_attribute_u32(&e, b"p3").ok(),
364 pid: get_attribute_u32(&e, b"pid").ok(),
365 };
366 visitor.on_displacement_triangle(&triangle)?;
367 }
368 Event::End(e) if e.local_name().as_ref() == b"triangles" => break,
369 Event::Eof => {
370 return Err(Lib3mfError::Validation(
371 "Unexpected EOF in displacement triangles".to_string(),
372 ));
373 }
374 _ => {}
375 }
376 }
377 Ok(())
378}
379
380fn parse_displacement_normals_streaming<R: BufRead, V: ModelVisitor>(
381 parser: &mut XmlParser<R>,
382 visitor: &mut V,
383) -> Result<()> {
384 loop {
385 match parser.read_next_event()? {
386 Event::Start(e) | Event::Empty(e) if e.local_name().as_ref() == b"normvector" => {
387 let nx = get_attribute_f32(&e, b"nx")?;
388 let ny = get_attribute_f32(&e, b"ny")?;
389 let nz = get_attribute_f32(&e, b"nz")?;
390 visitor.on_displacement_normal(nx, ny, nz)?;
391 }
392 Event::End(e) if e.local_name().as_ref() == b"normvectors" => break,
393 Event::Eof => {
394 return Err(Lib3mfError::Validation(
395 "Unexpected EOF in displacement normals".to_string(),
396 ));
397 }
398 _ => {}
399 }
400 }
401 Ok(())
402}
403
404fn parse_build_streaming<R: BufRead, V: ModelVisitor>(
405 parser: &mut XmlParser<R>,
406 visitor: &mut V,
407) -> Result<()> {
408 loop {
409 match parser.read_next_event()? {
410 Event::Start(e) | Event::Empty(e) => {
411 if e.name().as_ref() == b"item" {
412 let object_id = ResourceId(get_attribute_u32(&e, b"objectid")?);
413 let item = BuildItem {
414 object_id,
415 transform: Mat4::IDENTITY,
416 part_number: None,
417 uuid: None,
418 path: None,
419 printable: None,
420 };
421 visitor.on_build_item(&item)?;
422 }
423 }
424 Event::End(e) if e.name().as_ref() == b"build" => break,
425 Event::Eof => {
426 return Err(Lib3mfError::Validation(
427 "Unexpected EOF in build".to_string(),
428 ));
429 }
430 _ => {}
431 }
432 }
433 Ok(())
434}