dae_parser/core/
geom.rs

1use crate::*;
2
3/// Describes the visual shape and appearance of an object in a scene.
4#[derive(Clone, Debug)]
5pub struct Geometry {
6    /// A text string containing the unique identifier of the element.
7    pub id: Option<String>,
8    /// The text string name of this element.
9    pub name: Option<String>,
10    /// Asset management information about this element.
11    pub asset: Option<Box<Asset>>,
12    /// The element that describes geometric data.
13    pub element: GeometryElement,
14    /// Provides arbitrary additional information about this element.
15    pub extra: Vec<Extra>,
16}
17
18impl Geometry {
19    /// Construct a new `Geometry` given an `id` and the underlying element data.
20    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    /// Construct a new `Geometry` containing a [`Mesh`].
31    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/// Extra data associated to [`Instance`]<[`Geometry`]>.
77#[derive(Clone, Debug, Default)]
78pub struct InstanceGeometryData {
79    /// Binds material symbols to material instances. This allows a
80    /// single geometry to be instantiated into a scene multiple times
81    /// each with a different appearance.
82    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    /// Get the list of [`InstanceMaterial`]s bound in this [`Instance<Geometry>`].
106    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    /// Look up an [`InstanceMaterial`] by symbol name.
114    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/// An element that describes geometric data.
121#[derive(Clone, Debug)]
122pub enum GeometryElement {
123    /// The parameter is a URI string of a `Geometry`, and this element
124    /// describes the convex hull of the specified mesh.
125    ConvexHullOf(Url),
126    /// A mesh or convex mesh.
127    Mesh(Mesh),
128    /// A multisegment spline.
129    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    /// Parse a [`GeometryElement`] from an XML element.
156    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    /// The `sources` field, which gives the list of [`Source`] elements on this element.
166    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    /// Returns this element if it is a `<mesh>`.
175    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/// Describes basic geometric meshes using vertex and primitive information.
198#[derive(Clone, Debug)]
199pub struct Mesh {
200    /// If true, this is a `<convex_mesh>` element.
201    /// Both elements have the same structure otherwise.
202    pub convex: bool,
203    /// Provides the bulk of the mesh’s vertex data.
204    pub sources: Vec<Source>,
205    /// Describes the mesh-vertex attributes and establishes their topological identity.
206    pub vertices: Option<Vertices>,
207    /// Geometric primitives, which assemble values from the
208    /// inputs into vertex attribute data.
209    pub elements: Vec<Primitive>,
210    /// Provides arbitrary additional information about this element.
211    pub extra: Vec<Extra>,
212}
213
214impl Mesh {
215    /// Construct a new `Mesh` from vertices and elements.
216    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    /// Construct a new convex `Mesh` from vertices and elements.
228    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    /// The name of the XML node: `convex_mesh`
240    pub const CONVEX: &'static str = "convex_mesh";
241
242    /// Parse a `<convex_mesh>` XML element.
243    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    /// Parse a [`Mesh`] from an XML element of type `<convex_mesh>` or `<mesh>`.
252    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/// Declares the attributes and identity of mesh-vertices.
291#[derive(Clone, Debug)]
292pub struct Vertices {
293    /// A text string containing the unique identifier of the element.
294    /// This value must be unique within the document.
295    pub id: String,
296    /// The text string name of this element.
297    pub name: Option<String>,
298    /// The list of inputs.
299    pub inputs: Vec<Input>,
300    /// The index into `inputs` for the [`Semantic::Position`] input (which must exist).
301    pub position: usize,
302    /// Provides arbitrary additional information about this element.
303    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    /// Construct a new `Vertices` object with the given inputs.
359    /// * One of the inputs must have [`Semantic::Position`].
360    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    /// The input with [`Semantic::Position`].
374    pub fn position_input(&self) -> &Input {
375        &self.inputs[self.position]
376    }
377}
378
379/// The common data for the geometry types:
380///
381/// * [`Lines`]` = Geom<`[`LineGeom`]`>`
382/// * [`LineStrips`]` = Geom<`[`LineStripGeom`]`>`
383/// * [`Polygons`]` = Geom<`[`PolygonGeom`]`>`
384/// * [`PolyList`]` = Geom<`[`PolyListGeom`]`>`
385/// * [`Triangles`]` = Geom<`[`TriangleGeom`]`>`
386/// * [`TriFans`]` = Geom<`[`TriFanGeom`]`>`
387/// * [`TriStrips`]` = Geom<`[`TriStripGeom`]`>`
388#[derive(Clone, Default, Debug)]
389pub struct Geom<T> {
390    /// The text string name of this element.
391    pub name: Option<String>,
392    /// Declares a symbol for a material.
393    /// This symbol is bound to a material at the time of instantiation;
394    /// see [`Instance<Geometry>`] and [`BindMaterial`].
395    /// If not specified then the lighting and shading results are application defined.
396    pub material: Option<String>,
397    /// The number of line/triangle/polygon primitives.
398    pub count: usize,
399    /// The vertex attribute access information.
400    pub inputs: InputList,
401    /// The specific data for the geometry element.
402    pub data: T,
403    /// Provides arbitrary additional information about this element.
404    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    /// The trait for types that can appear in a [`Geom<T>`].
424    pub trait ParseGeom: XNodeWrite + Default {
425        /// The name of the element for the enclosing `Geom`, for example
426        /// `"lines"` for [`LineGeom`].
427        const NAME: &'static str;
428
429        /// Parse the data from an element iterator.
430        fn parse(it: &mut ElementIter<'_>) -> Result<Self>;
431
432        /// Perform custom validation on the resulting [`Geom<T>`] before yielding it.
433        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        /// A collection of primitive elements.
473        #[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            /// Parse a [`Primitive`] from an XML element.
488            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                /// An accessor for the variant.
497                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    /// Line primitives.
519    Lines(as_lines),
520    /// Line-strip primitives.
521    LineStrips(as_line_strips),
522    /// Polygon primitives which may contain holes.
523    Polygons(as_polygons),
524    /// Polygon primitives that cannot contain holes.
525    PolyList(as_polylist),
526    /// Triangle primitives.
527    Triangles(as_triangles),
528    /// Triangle-fan primitives.
529    TriFans(as_trifans),
530    /// Triangle-strip primitives.
531    TriStrips(as_tristrips),
532}
533
534/// The data for a [`Lines`] element.
535///
536/// Each line described by the mesh has two vertices.
537/// The first line is formed from the first and second vertices.
538/// The second line is formed from the third and fourth vertices, and so on.
539#[derive(Clone, Default, Debug)]
540pub struct LineGeom {
541    /// Contains indices that describe the vertex attributes for an
542    /// arbitrary number of individual lines.
543    pub prim: Option<Box<[u32]>>,
544}
545
546/// Provides the information needed for a mesh to bind vertex attributes
547/// together and then organize those vertices into individual lines.
548pub type Lines = Geom<LineGeom>;
549
550impl Lines {
551    /// Construct a new `Lines` object from a data buffer.
552    /// The data buffer `prim` contains exactly `count` lines, consisting of 2 vertices,
553    /// each consisting of `inputs.len()` indices,
554    /// for a total of `inputs.len() * 2 * count` values.
555    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/// The data for a [`LineStrips`] element.
601///
602/// Each line-strip described by the mesh has an arbitrary number of vertices.
603/// Each line segment within the line-strip is formed from the current vertex and the preceding vertex.
604#[derive(Clone, Default, Debug)]
605pub struct LineStripGeom {
606    /// Contains indices that describe the vertex attributes for an
607    /// arbitrary number of connected line segments.
608    pub prim: Vec<Box<[u32]>>,
609}
610
611/// Provides the information needed to bind vertex attributes together and then organize those vertices into
612/// connected line-strips.
613pub type LineStrips = Geom<LineStripGeom>;
614
615impl LineStrips {
616    /// Construct a new `LineStrips` object from a data buffer.
617    /// Each buffer in `data` contains 2 or more vertices,
618    /// each consisting of `inputs.len()` indices,
619    /// for a total of `inputs.len() * verts` values.
620    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/// The data for an individual polygon-with-hole.
664#[derive(Clone, Debug)]
665pub struct PolygonHole {
666    /// The vertex data for the polygon.
667    pub verts: Box<[u32]>,
668    /// A list of 0 or more holes, each of which describes a polygonal hole
669    /// in the main polygon.
670    pub hole: Vec<Box<[u32]>>,
671}
672
673impl PolygonHole {
674    /// Construct a new `PolygonHole` from a list of vertices and 0 or more holes.
675    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/// The data for a [`Polygons`] element.
690#[derive(Clone, Default, Debug)]
691pub struct PolygonGeom(
692    /// The list of polygons, each of which may contain 0 or more holes.
693    pub Vec<PolygonHole>,
694);
695
696/// Provides the information needed for a mesh to bind vertex attributes
697/// together and then organize those vertices into individual polygons.
698pub type Polygons = Geom<PolygonGeom>;
699
700impl Polygons {
701    /// Construct a new `Polygons` object from raw data.
702    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/// The data for a [`PolyList`] element.
765#[derive(Clone, Default, Debug)]
766pub struct PolyListGeom {
767    /// Contains a list of integers, each specifying the number of
768    /// vertices for one polygon described by the [`PolyList`] element.
769    pub vcount: Box<[u32]>,
770    /// Contains a list of integers that specify the vertex attributes
771    /// (indices) for an individual polylist.
772    /// The winding order of vertices produced is counter-clockwise
773    /// and describes the front side of each polygon.
774    pub prim: Box<[u32]>,
775}
776
777/// Provides the information needed for a mesh to bind vertex attributes
778/// together and then organize those vertices into individual polygons.
779pub type PolyList = Geom<PolyListGeom>;
780
781impl PolyList {
782    /// Construct a new `PolyList` object from a data buffer.
783    /// Each value `n` in `vcount` corresponds to a polygon with `n` vertices,
784    /// to which `inputs.len() * n` index values are associated in `prim`.
785    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/// The data for a [`Triangles`] element.
850///
851/// Each triangle described by the mesh has three vertices.
852/// The first triangle is formed from the first, second, and third vertices.
853/// The second triangle is formed from the fourth, fifth, and sixth vertices, and so on.
854#[derive(Clone, Default, Debug)]
855pub struct TriangleGeom {
856    /// Contains indices that describe the vertex attributes for a number of triangles.
857    /// The indices reference into the parent’s [`Source`] elements that are
858    /// referenced by the [`InputS`] elements.
859    pub prim: Option<Box<[u32]>>,
860}
861
862/// Provides the information needed for a mesh to bind vertex attributes
863/// together and then organize those vertices into individual triangles.
864pub type Triangles = Geom<TriangleGeom>;
865
866impl Triangles {
867    /// Construct a new `Triangles` object from a data buffer.
868    /// The data buffer `prim` contains exactly `count` triangles, consisting of 3 vertices,
869    /// each consisting of `inputs.len()` indices,
870    /// for a total of `inputs.len() * 3 * count` values.
871    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/// The data for a [`TriFans`] element.
917///
918/// Each triangle described by the mesh has three vertices.
919/// The first triangle is formed from the first, second, and third vertices.
920/// Each subsequent triangle is formed from the current vertex,
921/// reusing the first and the previous vertices.
922#[derive(Clone, Default, Debug)]
923pub struct TriFanGeom {
924    /// Contains indices that describe the vertex attributes for an
925    /// arbitrary number of connected triangles.
926    /// The indices reference into the parent’s [`Source`] elements that are
927    /// referenced by the [`InputS`] elements.
928    pub prim: Vec<Box<[u32]>>,
929}
930
931/// Provides the information needed for a mesh to bind vertex attributes
932/// together and then organize those vertices into connected triangles.
933pub type TriFans = Geom<TriFanGeom>;
934
935impl TriFans {
936    /// Construct a new `TriFans` object from a data buffer.
937    /// Each buffer in `data` contains 3 or more vertices,
938    /// each consisting of `inputs.len()` indices,
939    /// for a total of `inputs.len() * verts` values.
940    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/// The data for a [`TriStrips`] element.
982///
983/// Each triangle described by the mesh has three vertices.
984/// The first triangle is formed from the first, second, and third vertices.
985/// Each subsequent triangle is formed from the current vertex,
986/// reusing the previous two vertices.
987#[derive(Clone, Default, Debug)]
988pub struct TriStripGeom {
989    /// Contains indices that describe the vertex attributes for an
990    /// arbitrary number of connected triangles.
991    /// The indices reference into the parent’s [`Source`] elements that are
992    /// referenced by the [`InputS`] elements.
993    pub prim: Vec<Box<[u32]>>,
994}
995
996/// Provides the information needed for a mesh to bind vertex attributes
997/// together and then organize those vertices into connected triangles.
998pub type TriStrips = Geom<TriStripGeom>;
999
1000impl TriStrips {
1001    /// Construct a new `TriStrips` object from a data buffer.
1002    /// Each buffer in `data` contains 3 or more vertices,
1003    /// each consisting of `inputs.len()` indices,
1004    /// for a total of `inputs.len() * verts` values.
1005    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/// Describes a multisegment spline with control vertex (CV) and segment information.
1047#[derive(Clone, Debug)]
1048pub struct Spline {
1049    /// Whether there is a segment connecting the first and last control vertices.
1050    /// The default is "false", indicating that the spline is open.
1051    pub closed: bool,
1052    /// Provides the values for the CVs and segments of the spline.
1053    pub sources: Vec<Source>,
1054    /// Describes the CVs of the spline.
1055    pub controls: ControlVertices,
1056    /// Provides arbitrary additional information about this element.
1057    pub extra: Vec<Extra>,
1058}
1059
1060impl Spline {
1061    /// Construct a new `Spline` object with the given inputs.
1062    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/// Describes the control vertices (CVs) of a spline.
1099#[derive(Clone, Debug)]
1100pub struct ControlVertices {
1101    /// The list of inputs.
1102    pub inputs: Vec<Input>,
1103    /// The index into `inputs` for the [`Semantic::Position`] input (which must exist).
1104    pub position: usize,
1105    /// Provides arbitrary additional information about this element.
1106    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    /// Construct a new `Vertices` object with the given inputs.
1137    /// * One of the inputs must have [`Semantic::Position`].
1138    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    /// The input with [`Semantic::Position`].
1150    pub fn position_input(&self) -> &Input {
1151        &self.inputs[self.position]
1152    }
1153}