1use super::*;
2
3#[derive(Default)]
9pub(super) struct LibraryGeometries<'a> {
10 pub(super) geometries: BTreeMap<&'a str, Geometry<'a>>,
15
16 pub(super) accessors: HashMap<&'a str, Accessor<'a>>,
17 pub(super) array_data: HashMap<&'a str, ArrayData<'a>>,
18}
19
20pub(super) struct Geometry<'a> {
26 pub(super) id: &'a str,
28 pub(super) mesh: Mesh<'a>,
31}
32
33pub(super) struct Mesh<'a> {
39 pub(super) vertices: Vertices<'a>,
40 pub(super) primitives: Vec<Primitive<'a>>,
41}
42
43pub(super) struct Vertices<'a> {
44 pub(super) id: &'a str,
46 pub(super) input: VerticesInputs<'a>,
49}
50
51pub(super) struct VerticesInputs<'a> {
52 pub(super) position: UnsharedInput<'a>,
53 pub(super) normal: Option<UnsharedInput<'a>>,
54 pub(super) texcoord: Option<UnsharedInput<'a>>,
55 pub(super) color: Option<UnsharedInput<'a>>,
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
59pub(super) enum PrimitiveType {
60 Lines,
62 LineStrips,
64 Polygons,
66 Polylist,
68 Triangles,
70 TriFans,
72 TriStrips,
74}
75
76impl PrimitiveType {
77 pub(super) fn face_size(self) -> Option<u32> {
78 match self {
79 PrimitiveType::Lines | PrimitiveType::LineStrips => Some(2),
80 PrimitiveType::Triangles | PrimitiveType::TriFans | PrimitiveType::TriStrips => Some(3),
81 PrimitiveType::Polygons | PrimitiveType::Polylist => None,
82 }
83 }
84
85 pub(super) fn min_face_size(self) -> u32 {
86 self.face_size().unwrap_or(1)
87 }
88}
89
90pub(super) struct PrimitiveInputs<'a> {
91 pub(super) vertex: SharedInput<'a, Vertices<'a>>,
92 pub(super) normal: Option<SharedInput<'a>>,
93 pub(super) color: Option<SharedInput<'a>>,
94 pub(super) texcoord: Vec<SharedInput<'a>>,
95}
96
97pub(super) struct Primitive<'a> {
98 pub(super) ty: PrimitiveType,
100
101 pub(super) count: u32,
105 pub(super) material: Option<&'a str>,
107
108 pub(super) input: Option<PrimitiveInputs<'a>>,
110 pub(super) vcount: Vec<u32>,
132 pub(super) p: Vec<u32>,
134
135 pub(super) stride: u32,
136}
137
138pub(super) fn parse_library_geometries<'a>(
142 cx: &mut Context<'a>,
143 node: xml::Node<'a, '_>,
144) -> io::Result<()> {
145 debug_assert_eq!(node.tag_name().name(), "library_geometries");
146 for node in node.element_children() {
150 match node.tag_name().name() {
151 "geometry" => {
152 if let Some(geometry) = parse_geometry(cx, node)? {
153 cx.library_geometries
154 .geometries
155 .insert(geometry.id, geometry);
156 }
157 }
158 "asset" | "extra" => { }
159 _ => return Err(error::unexpected_child_elem(node)),
160 }
161 }
162
163 if cx.library_geometries.geometries.is_empty() {
164 return Err(error::one_or_more_elems(node, "geometry"));
165 }
166
167 Ok(())
168}
169
170fn parse_geometry<'a>(
171 cx: &mut Context<'a>,
172 node: xml::Node<'a, '_>,
173) -> io::Result<Option<Geometry<'a>>> {
174 debug_assert_eq!(node.tag_name().name(), "geometry");
175 let id = node.required_attribute("id")?;
177 let mut mesh = None;
178
179 for node in node.element_children() {
180 match node.tag_name().name() {
181 "mesh" => {
182 mesh = Some(parse_mesh(cx, node)?);
183 }
184 "convex_mesh" | "spline" | "brep" => {
185 return Ok(None);
192 }
193 "asset" | "extra" => { }
194 _ => return Err(error::unexpected_child_elem(node)),
195 }
196 }
197
198 let mesh = match mesh {
199 Some(mesh) => mesh,
200 None => return Err(error::one_or_more_elems(node, "mesh")),
201 };
202
203 Ok(Some(Geometry {
204 id,
205 mesh,
207 }))
208}
209
210fn parse_mesh<'a>(cx: &mut Context<'a>, node: xml::Node<'a, '_>) -> io::Result<Mesh<'a>> {
211 debug_assert_eq!(node.tag_name().name(), "mesh");
212 let mut primitives = vec![];
213 let mut has_source = false;
214 let mut vertices = None;
215
216 for node in node.element_children() {
217 let name = node.tag_name().name();
218 match name {
219 "source" => {
220 has_source = true;
221 let s = Source::parse(node)?;
222 if let Some(acc) = s.accessor {
223 cx.library_geometries.accessors.insert(s.id, acc);
224 }
225 if let Some(data) = s.array_element {
226 cx.library_geometries.array_data.insert(data.id, data.data);
227 }
228 }
229 "vertices" => {
230 vertices = Some(parse_vertices(node)?);
231 }
232 "lines" | "linestrips" | "polygons" | "polylist" | "triangles" | "trifans"
233 | "tristrips" => {
234 primitives.push(parse_primitive(node, name.parse().unwrap())?);
235 }
236 "extra" => { }
237 _ => return Err(error::unexpected_child_elem(node)),
238 }
239 }
240
241 if !has_source {
242 return Err(error::one_or_more_elems(node, "source"));
243 }
244 let vertices = match vertices {
245 Some(vertices) => vertices,
246 None => return Err(error::exactly_one_elem(node, "vertices")),
247 };
248
249 Ok(Mesh {
250 vertices,
251 primitives,
252 })
253}
254
255fn parse_vertices<'a>(node: xml::Node<'a, '_>) -> io::Result<Vertices<'a>> {
256 debug_assert_eq!(node.tag_name().name(), "vertices");
257 let id = node.required_attribute("id")?;
258
259 let mut input_position = None;
260 let mut input_normal = None;
261 let mut input_texcoord = None;
262 let mut input_color = None;
263
264 for node in node.element_children() {
265 match node.tag_name().name() {
266 "input" => {
267 let i = UnsharedInput::parse(node)?;
268 match i.semantic {
269 InputSemantic::POSITION => input_position = Some(i),
270 InputSemantic::NORMAL => input_normal = Some(i),
271 InputSemantic::TEXCOORD => input_texcoord = Some(i),
272 InputSemantic::COLOR => input_color = Some(i),
273 _semantic => {
274 }
280 }
281 }
282 "extra" => { }
283 _ => return Err(error::unexpected_child_elem(node)),
284 }
285 }
286
287 let input_position = match input_position {
289 Some(input_position) => input_position,
290 None => return Err(error::one_or_more_elems(node, "input")),
291 };
292
293 Ok(Vertices {
294 id,
295 input: VerticesInputs {
297 position: input_position,
298 normal: input_normal,
299 texcoord: input_texcoord,
300 color: input_color,
301 },
302 })
303}
304
305impl FromStr for PrimitiveType {
306 type Err = io::Error;
307
308 fn from_str(s: &str) -> Result<Self, Self::Err> {
309 Ok(match s {
310 "lines" => Self::Lines,
311 "linestrips" => Self::LineStrips,
312 "polygons" => Self::Polygons,
313 "polylist" => Self::Polylist,
314 "triangles" => Self::Triangles,
315 "trifans" => Self::TriFans,
316 "tristrips" => Self::TriStrips,
317 _ => bail!("unknown primitive type {:?}", s),
318 })
319 }
320}
321
322fn parse_primitive<'a>(node: xml::Node<'a, '_>, ty: PrimitiveType) -> io::Result<Primitive<'a>> {
323 debug_assert_eq!(node.tag_name().name().parse::<PrimitiveType>().unwrap(), ty);
324 let count: u32 = node.parse_required_attribute("count")?;
325 let mut vcount = vec![];
326 let mut p = vec![];
327 let mut stride = 0;
328
329 let mut input_vertex = None;
330 let mut input_normal = None;
331 let mut input_color = None;
332 let mut input_texcoord = vec![];
333
334 for node in node.element_children() {
335 match node.tag_name().name() {
336 "input" => {
337 let i = SharedInput::parse(node)?;
338 stride = cmp::max(stride, i.offset + 1);
339 match i.semantic {
340 InputSemantic::VERTEX => {
341 if i.set == 0 {
343 input_vertex = Some(i);
344 }
345 }
346 InputSemantic::NORMAL => {
347 if i.set == 0 {
349 input_normal = Some(i);
350 }
351 }
352 InputSemantic::COLOR => input_color = Some(i),
353 InputSemantic::TEXCOORD => input_texcoord.push(i),
354 _semantic => {
355 }
361 }
362 }
363 "vcount" => {
364 if ty != PrimitiveType::Polylist {
366 return Err(error::unexpected_child_elem(node));
367 }
368 if !vcount.is_empty() {
369 return Err(error::multiple_elems(node));
370 }
371 if count == 0 {
373 continue;
374 }
375
376 vcount.reserve(count as usize);
377
378 let mut iter = xml::parse_int_array::<u32>(node.trimmed_text());
380 for _ in 0..count {
381 let value = iter.next().ok_or_else(|| {
382 format_err!(
383 "expected more values while reading <{}> contents at {}",
384 node.tag_name().name(),
385 node.node_location()
386 )
387 })??;
388 if value >= 1 {
389 vcount.push(value);
390 } else {
391 bail!(
392 "incorrect number of indices in <p> element ({})",
393 node.node_location()
394 );
395 }
396 }
397 }
398 "p" => {
399 if count == 0 {
401 continue;
402 }
403
404 if matches!(
405 ty,
406 PrimitiveType::Lines | PrimitiveType::Polylist | PrimitiveType::Triangles
407 ) {
408 if !p.is_empty() {
412 return Err(error::multiple_elems(node));
413 }
414
415 let mut expected_count = 0;
416 match ty {
417 PrimitiveType::Polylist => {
418 for &i in &vcount {
419 expected_count += i as usize;
420 }
421 }
422 PrimitiveType::Lines => {
423 expected_count = count as usize * 2;
424 }
425 PrimitiveType::Triangles => {
426 expected_count = count as usize * 3;
427 }
428 _ => unreachable!(),
429 }
430
431 p.reserve(expected_count * stride as usize);
432
433 for value in xml::parse_int_array(node.trimmed_text()) {
436 p.push(value.map_err(|e| {
437 format_err!(
438 "{e} in <{}> element ({})",
439 node.tag_name().name(),
440 node.text_location(),
441 )
442 })?);
443 }
444
445 if p.len() != expected_count * stride as usize {
446 bail!(
448 "incorrect index count in <p> element, expected {} but found {} ({})",
449 expected_count * stride as usize,
450 p.len(),
451 node.node_location()
452 );
453 }
454 } else {
455 if vcount.capacity() == 0 {
461 vcount.reserve(count as usize);
462 }
463
464 let prev_len = p.len();
465
466 for value in xml::parse_int_array(node.trimmed_text()) {
469 p.push(value.map_err(|e| {
470 format_err!(
471 "{e} in <{}> element ({})",
472 node.tag_name().name(),
473 node.text_location(),
474 )
475 })?);
476 }
477
478 #[allow(clippy::cast_possible_truncation)]
479 let added = (p.len() - prev_len) as u32;
480 if added % stride != 0 {
481 bail!(
482 "incorrect index count in <p> element, expected multiple of {}, but found {} ({})",
483 stride,
484 p.len(),
485 node.node_location()
486 );
487 }
488 let vc = added / stride;
489 if vc >= ty.min_face_size() {
490 vcount.push(vc);
491 } else {
492 bail!(
493 "incorrect number of indices in <p> element ({})",
494 node.node_location()
495 );
496 }
497 }
498 }
499 "ph" => {
500 }
507 "extra" => { }
508 _ => return Err(error::unexpected_child_elem(node)),
509 }
510 }
511
512 if input_vertex.is_none()
514 && (input_normal.is_some() || input_color.is_some() || !input_texcoord.is_empty())
515 {
516 bail!(
517 "one <input> in <{}> element must specify semantic=\"VERTEX\" ({})",
518 node.tag_name().name(),
519 node.node_location()
520 );
521 }
522 if !input_texcoord.is_empty() {
524 input_texcoord.sort_by_key(|i| i.set);
525 }
526
527 Ok(Primitive {
528 ty,
529 count,
531 material: node.attribute("material"),
532 input: input_vertex.map(|vertex| PrimitiveInputs {
533 vertex: vertex.cast(),
534 normal: input_normal,
535 color: input_color,
536 texcoord: input_texcoord,
537 }),
538 vcount,
539 p,
540 stride,
541 })
542}