1use crate::*;
2
3#[derive(Clone, Debug)]
5pub struct Geometry {
6 pub id: Option<String>,
8 pub name: Option<String>,
10 pub asset: Option<Box<Asset>>,
12 pub element: GeometryElement,
14 pub extra: Vec<Extra>,
16}
17
18impl Geometry {
19 pub fn new(id: impl Into<String>, element: GeometryElement) -> Self {
21 Self {
22 id: Some(id.into()),
23 name: None,
24 asset: None,
25 element,
26 extra: vec![],
27 }
28 }
29
30 pub fn new_mesh(
32 id: impl Into<String>,
33 sources: Vec<Source>,
34 vertices: Vertices,
35 elements: Vec<Primitive>,
36 ) -> Self {
37 Self::new(id, Mesh::new(sources, vertices, elements).into())
38 }
39}
40
41impl XNode for Geometry {
42 const NAME: &'static str = "geometry";
43 fn parse(element: &Element) -> Result<Self> {
44 debug_assert_eq!(element.name(), Self::NAME);
45 let mut it = element.children().peekable();
46 Ok(Geometry {
47 id: element.attr("id").map(Into::into),
48 name: element.attr("name").map(Into::into),
49 asset: Asset::parse_opt_box(&mut it)?,
50 element: parse_one_many(&mut it, GeometryElement::parse)?,
51 extra: Extra::parse_many(it)?,
52 })
53 }
54}
55
56impl XNodeWrite for Geometry {
57 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
58 let mut e = Self::elem();
59 e.opt_attr("id", &self.id);
60 e.opt_attr("name", &self.name);
61 let e = e.start(w)?;
62 self.asset.write_to(w)?;
63 self.element.write_to(w)?;
64 self.extra.write_to(w)?;
65 e.end(w)
66 }
67}
68
69impl CollectLocalMaps for Geometry {
70 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
71 maps.insert(self);
72 self.element.collect_local_maps(maps);
73 }
74}
75
76#[derive(Clone, Debug, Default)]
78pub struct InstanceGeometryData {
79 pub bind_material: Option<BindMaterial>,
83}
84
85impl XNodeWrite for InstanceGeometryData {
86 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
87 self.bind_material.write_to(w)
88 }
89}
90
91impl Instantiate for Geometry {
92 const INSTANCE: &'static str = "instance_geometry";
93 type Data = InstanceGeometryData;
94 fn parse_data(_: &Element, it: &mut ElementIter<'_>) -> Result<Self::Data> {
95 Ok(InstanceGeometryData {
96 bind_material: BindMaterial::parse_opt(it)?,
97 })
98 }
99 fn is_empty(data: &Self::Data) -> bool {
100 data.bind_material.is_none()
101 }
102}
103
104impl Instance<Geometry> {
105 pub fn instance_materials(&self) -> &[InstanceMaterial] {
107 match self.data.bind_material {
108 Some(ref m) => &m.instance_material,
109 None => &[],
110 }
111 }
112
113 pub fn get_instance_material(&self, symbol: &str) -> Option<&InstanceMaterial> {
115 let bm = self.data.bind_material.as_ref()?;
116 bm.instance_material.iter().find(|mat| mat.symbol == symbol)
117 }
118}
119
120#[derive(Clone, Debug)]
122pub enum GeometryElement {
123 ConvexHullOf(Url),
126 Mesh(Mesh),
128 Spline(Spline),
130}
131
132impl From<Spline> for GeometryElement {
133 fn from(v: Spline) -> Self {
134 Self::Spline(v)
135 }
136}
137
138impl From<Mesh> for GeometryElement {
139 fn from(v: Mesh) -> Self {
140 Self::Mesh(v)
141 }
142}
143
144impl CollectLocalMaps for GeometryElement {
145 fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
146 match self {
147 GeometryElement::ConvexHullOf(_) => {}
148 GeometryElement::Mesh(mesh) => mesh.sources.collect_local_maps(maps),
149 GeometryElement::Spline(spline) => spline.sources.collect_local_maps(maps),
150 }
151 }
152}
153
154impl GeometryElement {
155 pub fn parse(element: &Element) -> Result<Option<Self>> {
157 Ok(Some(match element.name() {
158 Mesh::CONVEX => Mesh::parse_convex(element)?,
159 Mesh::NAME => GeometryElement::Mesh(Mesh::parse(false, element)?),
160 Spline::NAME => GeometryElement::Spline(Spline::parse(element)?),
161 _ => return Ok(None),
162 }))
163 }
164
165 pub fn sources(&self) -> &[Source] {
167 match self {
168 GeometryElement::ConvexHullOf(_) => &[],
169 GeometryElement::Mesh(mesh) => &mesh.sources,
170 GeometryElement::Spline(spline) => &spline.sources,
171 }
172 }
173
174 pub fn as_mesh(&self) -> Option<&Mesh> {
176 match self {
177 GeometryElement::Mesh(mesh) if !mesh.convex => Some(mesh),
178 _ => None,
179 }
180 }
181}
182
183impl XNodeWrite for GeometryElement {
184 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
185 match self {
186 GeometryElement::ConvexHullOf(s) => {
187 let mut e = ElemBuilder::new(Mesh::CONVEX);
188 e.print_attr("convex_hull_of", s);
189 e.end(w)
190 }
191 GeometryElement::Mesh(e) => e.write_to(w),
192 GeometryElement::Spline(e) => e.write_to(w),
193 }
194 }
195}
196
197#[derive(Clone, Debug)]
199pub struct Mesh {
200 pub convex: bool,
203 pub sources: Vec<Source>,
205 pub vertices: Option<Vertices>,
207 pub elements: Vec<Primitive>,
210 pub extra: Vec<Extra>,
212}
213
214impl Mesh {
215 pub fn new(sources: Vec<Source>, vertices: Vertices, elements: Vec<Primitive>) -> Self {
217 assert!(!sources.is_empty());
218 Self {
219 convex: false,
220 sources,
221 vertices: Some(vertices),
222 elements,
223 extra: vec![],
224 }
225 }
226
227 pub fn new_convex(sources: Vec<Source>, vertices: Vertices, elements: Vec<Primitive>) -> Self {
229 assert!(!sources.is_empty());
230 Self {
231 convex: true,
232 sources,
233 vertices: Some(vertices),
234 elements,
235 extra: vec![],
236 }
237 }
238
239 pub const CONVEX: &'static str = "convex_mesh";
241
242 pub fn parse_convex(element: &Element) -> Result<GeometryElement> {
244 debug_assert_eq!(element.name(), Self::CONVEX);
245 if let Some(s) = parse_attr(element.attr("convex_hull_of"))? {
246 return Ok(GeometryElement::ConvexHullOf(s));
247 }
248 Ok(GeometryElement::Mesh(Mesh::parse(true, element)?))
249 }
250
251 pub fn parse(convex: bool, element: &Element) -> Result<Self> {
253 debug_assert_eq!(
254 element.name(),
255 if convex { Self::CONVEX } else { Self::NAME }
256 );
257 let mut it = element.children().peekable();
258 Ok(Mesh {
259 convex,
260 sources: Source::parse_list_n::<1>(&mut it)?,
261 vertices: Vertices::parse_opt(&mut it)?,
262 elements: parse_list_many(&mut it, Primitive::parse)?,
263 extra: Extra::parse_many(it)?,
264 })
265 }
266
267 fn write_inner<W: Write>(&self, e: ElemBuilder, w: &mut XWriter<W>) -> Result<()> {
268 let e = e.start(w)?;
269 self.sources.write_to(w)?;
270 self.vertices.write_to(w)?;
271 self.elements.write_to(w)?;
272 self.extra.write_to(w)?;
273 e.end(w)
274 }
275}
276
277impl XNode for Mesh {
278 const NAME: &'static str = "mesh";
279 fn parse(element: &Element) -> Result<Self> {
280 Self::parse(false, element)
281 }
282}
283
284impl XNodeWrite for Mesh {
285 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
286 self.write_inner(Self::elem(), w)
287 }
288}
289
290#[derive(Clone, Debug)]
292pub struct Vertices {
293 pub id: String,
296 pub name: Option<String>,
298 pub inputs: Vec<Input>,
300 pub position: usize,
302 pub extra: Vec<Extra>,
304}
305
306impl XNode for Vertices {
307 const NAME: &'static str = "vertices";
308 fn parse(element: &Element) -> Result<Self> {
309 debug_assert_eq!(element.name(), Self::NAME);
310 let mut it = element.children().peekable();
311 let inputs = Input::parse_list(&mut it)?;
312 Ok(Vertices {
313 id: element.attr("id").ok_or("missing 'id' attr")?.into(),
314 name: element.attr("name").map(Into::into),
315 position: inputs
316 .iter()
317 .position(|i| i.semantic == Semantic::Position)
318 .ok_or("vertices: missing POSITION input")?,
319 inputs,
320 extra: Extra::parse_many(it)?,
321 })
322 }
323}
324
325impl XNodeWrite for Vertices {
326 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
327 let mut e = Self::elem();
328 e.attr("id", &self.id);
329 e.opt_attr("name", &self.name);
330 let e = e.start(w)?;
331 self.inputs.write_to(w)?;
332 self.extra.write_to(w)?;
333 e.end(w)
334 }
335}
336
337impl Traversable for Vertices {
338 fn traverse<'a, E>(
339 doc: &'a Document,
340 mut f: impl FnMut(&'a Self) -> Result<(), E>,
341 ) -> Result<(), E>
342 where
343 Self: 'a,
344 {
345 for lib in doc.iter::<Geometry>() {
346 if let GeometryElement::Mesh(Mesh {
347 vertices: Some(v), ..
348 }) = &lib.element
349 {
350 f(v)?
351 }
352 }
353 Ok(())
354 }
355}
356
357impl Vertices {
358 pub fn new(id: impl Into<String>, inputs: Vec<Input>) -> Self {
361 Self {
362 id: id.into(),
363 name: None,
364 position: inputs
365 .iter()
366 .position(|i| i.semantic == Semantic::Position)
367 .expect("vertices: missing POSITION input"),
368 inputs,
369 extra: vec![],
370 }
371 }
372
373 pub fn position_input(&self) -> &Input {
375 &self.inputs[self.position]
376 }
377}
378
379#[derive(Clone, Default, Debug)]
389pub struct Geom<T> {
390 pub name: Option<String>,
392 pub material: Option<String>,
397 pub count: usize,
399 pub inputs: InputList,
401 pub data: T,
403 pub extra: Vec<Extra>,
405}
406
407impl<T: ParseGeom> Geom<T> {
408 fn new_geom(material: Option<String>, inputs: InputList, count: usize, data: T) -> Self {
409 Self {
410 name: None,
411 material,
412 count,
413 inputs,
414 data,
415 extra: vec![],
416 }
417 }
418}
419
420pub(crate) use private::ParseGeom;
421pub(crate) mod private {
422 use super::*;
423 pub trait ParseGeom: XNodeWrite + Default {
425 const NAME: &'static str;
428
429 fn parse(it: &mut ElementIter<'_>) -> Result<Self>;
431
432 fn validate(_: &Geom<Self>) -> Result<()>;
434 }
435}
436
437impl<T: ParseGeom> XNode for Geom<T> {
438 const NAME: &'static str = T::NAME;
439
440 fn parse(element: &Element) -> Result<Self> {
441 debug_assert_eq!(element.name(), Self::NAME);
442 let mut it = element.children().peekable();
443 let res = Geom {
444 name: element.attr("name").map(Into::into),
445 material: element.attr("material").map(Into::into),
446 count: parse_attr(element.attr("count"))?.ok_or("expected 'count' attr")?,
447 inputs: InputList::parse::<0>(&mut it)?,
448 data: T::parse(&mut it)?,
449 extra: Extra::parse_many(it)?,
450 };
451 T::validate(&res)?;
452 Ok(res)
453 }
454}
455
456impl<T: ParseGeom> XNodeWrite for Geom<T> {
457 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
458 let mut e = Self::elem();
459 e.opt_attr("name", &self.name);
460 e.opt_attr("material", &self.material);
461 e.print_attr("count", self.count);
462 let e = e.start(w)?;
463 self.inputs.write_to(w)?;
464 self.data.write_to(w)?;
465 self.extra.write_to(w)?;
466 e.end(w)
467 }
468}
469
470macro_rules! mk_primitive {
471 ($($(#[$doc:meta])* $name:ident($as:ident),)*) => {
472 #[derive(Clone, Debug)]
474 pub enum Primitive {
475 $($(#[$doc])* $name($name),)*
476 }
477
478 $(
479 impl From<$name> for Primitive {
480 fn from(val: $name) -> Self {
481 Self::$name(val)
482 }
483 }
484 )*
485
486 impl Primitive {
487 pub fn parse(e: &Element) -> Result<Option<Self>> {
489 Ok(Some(match e.name() {
490 $($name::NAME => Self::$name(Geom::parse(e)?),)*
491 _ => return Ok(None),
492 }))
493 }
494
495 $(
496 pub fn $as(&self) -> Option<&$name> {
498 if let Self::$name(x) = self {
499 Some(x)
500 } else {
501 None
502 }
503 }
504 )*
505 }
506
507 impl XNodeWrite for Primitive {
508 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
509 match self {
510 $(Self::$name(e) => e.write_to(w),)*
511 }
512 }
513 }
514 }
515}
516
517mk_primitive! {
518 Lines(as_lines),
520 LineStrips(as_line_strips),
522 Polygons(as_polygons),
524 PolyList(as_polylist),
526 Triangles(as_triangles),
528 TriFans(as_trifans),
530 TriStrips(as_tristrips),
532}
533
534#[derive(Clone, Default, Debug)]
540pub struct LineGeom {
541 pub prim: Option<Box<[u32]>>,
544}
545
546pub type Lines = Geom<LineGeom>;
549
550impl Lines {
551 pub fn new(
556 material: Option<String>,
557 inputs: Vec<InputS>,
558 count: usize,
559 prim: Box<[u32]>,
560 ) -> Self {
561 let inputs = InputList::new(inputs);
562 assert!(inputs.len() * 2 * count == prim.len());
563 Self::new_geom(material, inputs, count, LineGeom { prim: Some(prim) })
564 }
565}
566
567impl Deref for LineGeom {
568 type Target = Option<Box<[u32]>>;
569
570 fn deref(&self) -> &Self::Target {
571 &self.prim
572 }
573}
574
575impl ParseGeom for LineGeom {
576 const NAME: &'static str = "lines";
577
578 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
579 Ok(LineGeom {
580 prim: parse_opt("p", it, parse_array)?,
581 })
582 }
583
584 fn validate(res: &Geom<Self>) -> Result<()> {
585 if let Some(ref data) = *res.data {
586 if res.inputs.stride * 2 * res.count != data.len() {
587 return Err("line count does not match <p> field".into());
588 }
589 }
590 Ok(())
591 }
592}
593
594impl XNodeWrite for LineGeom {
595 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
596 opt(&self.prim, |e| ElemBuilder::print_arr("p", e, w))
597 }
598}
599
600#[derive(Clone, Default, Debug)]
605pub struct LineStripGeom {
606 pub prim: Vec<Box<[u32]>>,
609}
610
611pub type LineStrips = Geom<LineStripGeom>;
614
615impl LineStrips {
616 pub fn new(material: Option<String>, inputs: Vec<InputS>, prim: Vec<Box<[u32]>>) -> Self {
621 let inputs = InputList::new(inputs);
622 debug_assert!(prim.iter().all(|p| inputs.check_prim::<2>(p)));
623 Self::new_geom(material, inputs, prim.len(), LineStripGeom { prim })
624 }
625}
626
627impl Deref for LineStripGeom {
628 type Target = Vec<Box<[u32]>>;
629
630 fn deref(&self) -> &Self::Target {
631 &self.prim
632 }
633}
634
635impl ParseGeom for LineStripGeom {
636 const NAME: &'static str = "line_strips";
637
638 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
639 Ok(LineStripGeom {
640 prim: parse_list("p", it, parse_array)?,
641 })
642 }
643
644 fn validate(res: &Geom<Self>) -> Result<()> {
645 if res.count != res.data.len() {
646 return Err("line strip count does not match <p> fields".into());
647 }
648 if !res.data.iter().all(|p| res.inputs.check_prim::<2>(p)) {
649 return Err("incorrect <p> field in line strips".into());
650 }
651 Ok(())
652 }
653}
654
655impl XNodeWrite for LineStripGeom {
656 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
657 self.prim
658 .iter()
659 .try_for_each(|e| ElemBuilder::print_arr("p", e, w))
660 }
661}
662
663#[derive(Clone, Debug)]
665pub struct PolygonHole {
666 pub verts: Box<[u32]>,
668 pub hole: Vec<Box<[u32]>>,
671}
672
673impl PolygonHole {
674 pub fn new(verts: Box<[u32]>, hole: Vec<Box<[u32]>>) -> Self {
676 Self { verts, hole }
677 }
678}
679
680impl XNodeWrite for PolygonHole {
681 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
682 let e = ElemBuilder::new("ph").start(w)?;
683 ElemBuilder::print_arr("p", &self.verts, w)?;
684 many(&self.hole, |h| ElemBuilder::print_arr("h", h, w))?;
685 e.end(w)
686 }
687}
688
689#[derive(Clone, Default, Debug)]
691pub struct PolygonGeom(
692 pub Vec<PolygonHole>,
694);
695
696pub type Polygons = Geom<PolygonGeom>;
699
700impl Polygons {
701 pub fn new(material: Option<String>, inputs: Vec<InputS>, prim: Vec<PolygonHole>) -> Self {
703 let inputs = InputList::new(inputs);
704 debug_assert!(prim.iter().all(|ph| {
705 inputs.check_prim::<3>(&ph.verts) && ph.hole.iter().all(|h| inputs.check_prim::<3>(h))
706 }));
707 Self::new_geom(material, inputs, prim.len(), PolygonGeom(prim))
708 }
709}
710
711impl Deref for PolygonGeom {
712 type Target = Vec<PolygonHole>;
713
714 fn deref(&self) -> &Self::Target {
715 &self.0
716 }
717}
718
719impl ParseGeom for PolygonGeom {
720 const NAME: &'static str = "polygon";
721
722 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
723 let mut polys = parse_list("p", it, |e| {
724 Ok(PolygonHole {
725 verts: parse_array(e)?,
726 hole: vec![],
727 })
728 })?;
729 let more_polys = parse_list("ph", it, |e| {
730 let mut it = e.children().peekable();
731 let verts = parse_one("p", &mut it, parse_array)?;
732 let hole = parse_list("h", &mut it, parse_array)?;
733 if hole.is_empty() {
734 return Err(
735 "<ph> element can only be used when at least one hole is present".into(),
736 );
737 }
738 finish(PolygonHole { verts, hole }, it)
739 })?;
740 polys.extend(more_polys);
741 Ok(PolygonGeom(polys))
742 }
743
744 fn validate(res: &Geom<Self>) -> Result<()> {
745 if res.count != res.data.len() {
746 return Err("polygon count does not match <p> fields".into());
747 }
748 if !res.data.iter().all(|ph| {
749 res.inputs.check_prim::<3>(&ph.verts)
750 && ph.hole.iter().all(|h| res.inputs.check_prim::<3>(h))
751 }) {
752 return Err("incorrect <p> field in polygon".into());
753 }
754 Ok(())
755 }
756}
757
758impl XNodeWrite for PolygonGeom {
759 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
760 self.0.write_to(w)
761 }
762}
763
764#[derive(Clone, Default, Debug)]
766pub struct PolyListGeom {
767 pub vcount: Box<[u32]>,
770 pub prim: Box<[u32]>,
775}
776
777pub type PolyList = Geom<PolyListGeom>;
780
781impl PolyList {
782 pub fn new(
786 material: Option<String>,
787 inputs: Vec<InputS>,
788 vcount: Box<[u32]>,
789 prim: Box<[u32]>,
790 ) -> Self {
791 let inputs = InputList::new(inputs);
792 debug_assert!(inputs.len() * vcount.iter().sum::<u32>() as usize == prim.len());
793 Self::new_geom(
794 material,
795 inputs,
796 vcount.len(),
797 PolyListGeom { vcount, prim },
798 )
799 }
800}
801
802pub(crate) fn validate_vcount<T>(
803 count: usize,
804 stride: usize,
805 vcount: &[u32],
806 prim: &[T],
807) -> Result<()> {
808 if count != vcount.len() {
809 return Err("count does not match <vcount> field".into());
810 }
811 if stride * vcount.iter().sum::<u32>() as usize != prim.len() {
812 return Err("vcount does not match <p>/<v> field".into());
813 }
814 Ok(())
815}
816
817impl ParseGeom for PolyListGeom {
818 const NAME: &'static str = "polylist";
819
820 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
821 Ok(PolyListGeom {
822 vcount: parse_opt("vcount", it, parse_array)?.unwrap_or_default(),
823 prim: parse_opt("p", it, parse_array)?.unwrap_or_default(),
824 })
825 }
826
827 fn validate(res: &Geom<Self>) -> Result<()> {
828 validate_vcount(
829 res.count,
830 res.inputs.stride,
831 &res.data.vcount,
832 &res.data.prim,
833 )
834 }
835}
836
837impl XNodeWrite for PolyListGeom {
838 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
839 if !self.vcount.is_empty() {
840 ElemBuilder::print_arr("vcount", &self.vcount, w)?;
841 }
842 if !self.prim.is_empty() {
843 ElemBuilder::print_arr("p", &self.prim, w)?;
844 }
845 Ok(())
846 }
847}
848
849#[derive(Clone, Default, Debug)]
855pub struct TriangleGeom {
856 pub prim: Option<Box<[u32]>>,
860}
861
862pub type Triangles = Geom<TriangleGeom>;
865
866impl Triangles {
867 pub fn new(
872 material: Option<String>,
873 inputs: Vec<InputS>,
874 count: usize,
875 prim: Box<[u32]>,
876 ) -> Self {
877 let inputs = InputList::new(inputs);
878 assert!(inputs.len() * 3 * count == prim.len());
879 Self::new_geom(material, inputs, count, TriangleGeom { prim: Some(prim) })
880 }
881}
882
883impl Deref for TriangleGeom {
884 type Target = Option<Box<[u32]>>;
885
886 fn deref(&self) -> &Self::Target {
887 &self.prim
888 }
889}
890
891impl ParseGeom for TriangleGeom {
892 const NAME: &'static str = "triangles";
893
894 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
895 Ok(TriangleGeom {
896 prim: parse_opt("p", it, parse_array)?,
897 })
898 }
899
900 fn validate(res: &Geom<Self>) -> Result<()> {
901 if let Some(ref data) = *res.data {
902 if res.inputs.stride * 3 * res.count != data.len() {
903 return Err("triangle count does not match <p> field".into());
904 }
905 }
906 Ok(())
907 }
908}
909
910impl XNodeWrite for TriangleGeom {
911 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
912 opt(&self.prim, |e| ElemBuilder::print_arr("p", e, w))
913 }
914}
915
916#[derive(Clone, Default, Debug)]
923pub struct TriFanGeom {
924 pub prim: Vec<Box<[u32]>>,
929}
930
931pub type TriFans = Geom<TriFanGeom>;
934
935impl TriFans {
936 pub fn new(material: Option<String>, inputs: Vec<InputS>, prim: Vec<Box<[u32]>>) -> Self {
941 let inputs = InputList::new(inputs);
942 debug_assert!(prim.iter().all(|p| inputs.check_prim::<3>(p)));
943 Self::new_geom(material, inputs, prim.len(), TriFanGeom { prim })
944 }
945}
946
947impl Deref for TriFanGeom {
948 type Target = Vec<Box<[u32]>>;
949
950 fn deref(&self) -> &Self::Target {
951 &self.prim
952 }
953}
954
955impl ParseGeom for TriFanGeom {
956 const NAME: &'static str = "trifans";
957
958 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
959 Ok(TriFanGeom {
960 prim: parse_list("p", it, parse_array)?,
961 })
962 }
963
964 fn validate(res: &Geom<Self>) -> Result<()> {
965 if res.count != res.data.len() {
966 return Err("triangle fan count does not match <p> fields".into());
967 }
968 if !res.data.iter().all(|p| res.inputs.check_prim::<3>(p)) {
969 return Err("incorrect <p> field in triangle fans".into());
970 }
971 Ok(())
972 }
973}
974
975impl XNodeWrite for TriFanGeom {
976 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
977 many(&self.prim, |e| ElemBuilder::print_arr("p", e, w))
978 }
979}
980
981#[derive(Clone, Default, Debug)]
988pub struct TriStripGeom {
989 pub prim: Vec<Box<[u32]>>,
994}
995
996pub type TriStrips = Geom<TriStripGeom>;
999
1000impl TriStrips {
1001 pub fn new(material: Option<String>, inputs: Vec<InputS>, prim: Vec<Box<[u32]>>) -> Self {
1006 let inputs = InputList::new(inputs);
1007 debug_assert!(prim.iter().all(|p| inputs.check_prim::<3>(p)));
1008 Self::new_geom(material, inputs, prim.len(), TriStripGeom { prim })
1009 }
1010}
1011
1012impl Deref for TriStripGeom {
1013 type Target = Vec<Box<[u32]>>;
1014
1015 fn deref(&self) -> &Self::Target {
1016 &self.prim
1017 }
1018}
1019
1020impl ParseGeom for TriStripGeom {
1021 const NAME: &'static str = "tristrips";
1022
1023 fn parse(it: &mut ElementIter<'_>) -> Result<Self> {
1024 Ok(TriStripGeom {
1025 prim: parse_list("p", it, parse_array)?,
1026 })
1027 }
1028
1029 fn validate(res: &Geom<Self>) -> Result<()> {
1030 if res.count != res.data.len() {
1031 return Err("triangle strip count does not match <p> fields".into());
1032 }
1033 if !res.data.iter().all(|p| res.inputs.check_prim::<3>(p)) {
1034 return Err("incorrect <p> field in triangle strips".into());
1035 }
1036 Ok(())
1037 }
1038}
1039
1040impl XNodeWrite for TriStripGeom {
1041 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
1042 many(&self.prim, |e| ElemBuilder::print_arr("p", e, w))
1043 }
1044}
1045
1046#[derive(Clone, Debug)]
1048pub struct Spline {
1049 pub closed: bool,
1052 pub sources: Vec<Source>,
1054 pub controls: ControlVertices,
1056 pub extra: Vec<Extra>,
1058}
1059
1060impl Spline {
1061 pub fn new(sources: Vec<Source>, controls: Vec<Input>) -> Self {
1063 Self {
1064 closed: false,
1065 sources,
1066 controls: ControlVertices::new(controls),
1067 extra: vec![],
1068 }
1069 }
1070}
1071
1072impl XNode for Spline {
1073 const NAME: &'static str = "spline";
1074 fn parse(element: &Element) -> Result<Self> {
1075 debug_assert_eq!(element.name(), Self::NAME);
1076 let mut it = element.children().peekable();
1077 Ok(Spline {
1078 closed: parse_attr(element.attr("closed"))?.unwrap_or(false),
1079 sources: Source::parse_list_n::<1>(&mut it)?,
1080 controls: ControlVertices::parse_one(&mut it)?,
1081 extra: Extra::parse_many(it)?,
1082 })
1083 }
1084}
1085
1086impl XNodeWrite for Spline {
1087 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
1088 let mut e = Self::elem();
1089 e.def_print_attr("closed", self.closed, false);
1090 let e = e.start(w)?;
1091 self.sources.write_to(w)?;
1092 self.controls.write_to(w)?;
1093 self.extra.write_to(w)?;
1094 e.end(w)
1095 }
1096}
1097
1098#[derive(Clone, Debug)]
1100pub struct ControlVertices {
1101 pub inputs: Vec<Input>,
1103 pub position: usize,
1105 pub extra: Vec<Extra>,
1107}
1108
1109impl XNode for ControlVertices {
1110 const NAME: &'static str = "control_vertices";
1111 fn parse(element: &Element) -> Result<Self> {
1112 debug_assert_eq!(element.name(), Self::NAME);
1113 let mut it = element.children().peekable();
1114 let inputs = Input::parse_list(&mut it)?;
1115 Ok(ControlVertices {
1116 position: inputs
1117 .iter()
1118 .position(|i| i.semantic == Semantic::Position)
1119 .ok_or("control_vertices: missing POSITION input")?,
1120 inputs,
1121 extra: Extra::parse_many(it)?,
1122 })
1123 }
1124}
1125
1126impl XNodeWrite for ControlVertices {
1127 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
1128 let e = Self::elem().start(w)?;
1129 self.inputs.write_to(w)?;
1130 self.extra.write_to(w)?;
1131 e.end(w)
1132 }
1133}
1134
1135impl ControlVertices {
1136 pub fn new(inputs: Vec<Input>) -> Self {
1139 Self {
1140 position: inputs
1141 .iter()
1142 .position(|i| i.semantic == Semantic::Position)
1143 .expect("control_vertices: missing POSITION input"),
1144 inputs,
1145 extra: vec![],
1146 }
1147 }
1148
1149 pub fn position_input(&self) -> &Input {
1151 &self.inputs[self.position]
1152 }
1153}