dae_parser/core/
data.rs

1use crate::*;
2
3/// Describes a stream of values from an array data source.
4#[derive(Clone, Debug)]
5pub struct Accessor {
6    /// The location of the array to access using a URI expression.
7    /// This element may refer to a COLLADA array element or to an
8    /// array data source outside the scope of the document;
9    /// the source does not need to be a COLLADA document.
10    pub source: Url,
11    /// The number of times the array is accessed.
12    pub count: usize,
13    /// The index of the first value to be read from the array.
14    pub offset: usize,
15    /// The number of values that are to be considered a unit during each access to the array.
16    /// The default is 1, indicating that a single value is accessed.
17    pub stride: usize,
18    /// The list of accesses.
19    pub param: Vec<Param>,
20}
21
22impl Accessor {
23    /// Construct a new `Accessor` from the mandatory data.
24    pub fn new(source: Url, count: usize, param: Vec<Param>) -> Self {
25        Self {
26            source,
27            count,
28            offset: 0,
29            stride: param.len(),
30            param,
31        }
32    }
33}
34
35impl XNode for Accessor {
36    const NAME: &'static str = "accessor";
37    fn parse(element: &Element) -> Result<Self> {
38        debug_assert_eq!(element.name(), Self::NAME);
39        let mut it = element.children().peekable();
40        let res = Accessor {
41            source: parse_attr(element.attr("source"))?.ok_or("missing source attr")?,
42            count: parse_attr(element.attr("count"))?.ok_or("expected 'count' attr")?,
43            offset: parse_attr(element.attr("offset"))?.unwrap_or(0),
44            stride: parse_attr(element.attr("stride"))?.unwrap_or(1),
45            param: Param::parse_list(&mut it)?,
46        };
47        if res.stride < res.param.len() {
48            return Err("accessor stride does not match params".into());
49        }
50        finish(res, it)
51    }
52}
53
54impl XNodeWrite for Accessor {
55    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
56        let mut e = Self::elem();
57        e.print_attr("source", &self.source);
58        e.print_attr("count", self.count);
59        e.def_print_attr("offset", self.offset, 0);
60        e.def_print_attr("stride", self.stride, 1);
61        let e = e.start(w)?;
62        self.param.write_to(w)?;
63        e.end(w)
64    }
65}
66
67fn parse_array_count<T: FromStr>(e: &Element) -> Result<Box<[T]>> {
68    let count: usize = parse_attr(e.attr("count"))?.ok_or("expected 'count' attr")?;
69    let mut vec = Vec::with_capacity(count);
70    for s in get_text(e)
71        .ok_or("expected text node")?
72        .split_ascii_whitespace()
73    {
74        vec.push(s.parse().map_err(|_| "parse error")?)
75    }
76    if vec.len() != count {
77        return Err("'count' does not match array length".into());
78    }
79    Ok(vec.into())
80}
81
82/// A trait for the common functionality of the array types.
83pub trait ArrayKind: HasId + XNode + Deref<Target = [Self::Elem]> + 'static {
84    /// The stored element type.
85    type Elem: Clone + Display + Debug + 'static;
86    /// Extract a typed array from an [`ArrayElement`].
87    fn from_array_element(elem: &ArrayElement) -> Option<&Self>;
88}
89
90macro_rules! mk_arrays {
91    ($($(#[$doc:meta])* $name:ident($tyname:ident[$ty:ty]) = $s:literal,)*) => {
92        $(
93            $(#[$doc])*
94            #[derive(Clone, Debug)]
95            pub struct $tyname {
96                /// A text string containing the unique identifier of the element.
97                pub id: Option<String>,
98                /// The stored array of values.
99                pub val: Box<[$ty]>,
100            }
101            impl $tyname {
102                /// Construct a new array element from an array.
103                pub fn new(id: impl Into<String>, val: Box<[$ty]>) -> Self {
104                    Self {
105                        id: Some(id.into()),
106                        val,
107                    }
108                }
109            }
110            impl From<$tyname> for ArrayElement {
111                fn from(val: $tyname) -> Self {
112                    Self::$name(val)
113                }
114            }
115            impl Deref for $tyname {
116                type Target = [$ty];
117
118                fn deref(&self) -> &Self::Target {
119                    &self.val
120                }
121            }
122            impl XNode for $tyname {
123                const NAME: &'static str = $s;
124                fn parse(element: &Element) -> Result<Self> {
125                    debug_assert_eq!(element.name(), Self::NAME);
126                    Ok(Self {
127                        id: element.attr("id").map(Into::into),
128                        val: parse_array_count(element)?,
129                    })
130                }
131            }
132            impl XNodeWrite for $tyname {
133                fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
134                    let mut e = Self::elem();
135                    e.opt_attr("id", &self.id);
136                    e.print_attr("count", self.val.len());
137                    let e = e.start(w)?;
138                    print_arr(&self.val, w)?;
139                    e.end(w)
140                }
141            }
142            impl CollectLocalMaps for $tyname {
143                fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
144                    maps.insert(self)
145                }
146            }
147            impl ArrayKind for $tyname {
148                type Elem = $ty;
149                fn from_array_element(elem: &ArrayElement) -> Option<&Self> {
150                    match elem {
151                        ArrayElement::$name(arr) => Some(arr),
152                        _ => None,
153                    }
154                }
155            }
156        )*
157
158        /// A data array element.
159        #[derive(Clone, Debug)]
160        pub enum ArrayElement {
161            $($(#[$doc])* $name($tyname),)*
162        }
163
164        impl XNodeWrite for ArrayElement {
165            fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
166                match self {
167                    $(Self::$name(e) => e.write_to(w),)*
168                }
169            }
170        }
171
172        impl CollectLocalMaps for ArrayElement {
173            fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
174                match self {
175                    $(Self::$name(arr) => arr.collect_local_maps(maps),)*
176                }
177            }
178        }
179
180        impl ArrayElement {
181            /// Parse an [`ArrayElement`] from an XML element.
182            pub fn parse(e: &Element) -> Result<Option<Self>> {
183                Ok(Some(match e.name() {
184                    $($tyname::NAME => Self::$name($tyname::parse(e)?),)*
185                    _ => return Ok(None),
186                }))
187            }
188
189            /// Get the ID of this element.
190            pub fn id(&self) -> Option<&str> {
191                match self {
192                    $(ArrayElement::$name(arr) => arr.id.as_deref(),)*
193                }
194            }
195
196            /// Get the number of values in this array.
197            pub fn len(&self) -> usize {
198                match self {
199                    $(ArrayElement::$name(arr) => arr.len(),)*
200                }
201            }
202
203            /// Returns true if the array is empty.
204            pub fn is_empty(&self) -> bool {
205                self.len() == 0
206            }
207        }
208    }
209}
210
211mk_arrays! {
212    /// Stores a homogenous array of ID reference values.
213    IdRef(IdRefArray[String]) = "IDREF_array",
214    /// Stores a homogenous array of symbolic name values.
215    Name(NameArray[String]) = "Name_array",
216    /// Stores a homogenous array of Boolean values.
217    Bool(BoolArray[bool]) = "bool_array",
218    /// Stores a homogenous array of floating-point values.
219    Float(FloatArray[f32]) = "float_array",
220    /// Stores a homogenous array of integer values.
221    Int(IntArray[u32]) = "int_array",
222}
223
224/// Declares parametric information for its parent element.
225#[derive(Clone, Debug)]
226pub struct Param {
227    /// A text string value containing the subidentifier of this element.
228    /// This value must be unique within the scope of the parent element.
229    pub sid: Option<String>,
230    /// The text string name of this element.
231    pub name: Option<String>,
232    /// The type of the value data. This text string must be understood by the application.
233    pub ty: String,
234    /// The user-defined meaning of the parameter.
235    pub semantic: Option<Semantic>,
236}
237
238impl Param {
239    /// Construct a new `Param` with given name and type.
240    pub fn new(name: impl Into<String>, ty: impl Into<String>) -> Self {
241        Self {
242            sid: None,
243            name: Some(name.into()),
244            ty: ty.into(),
245            semantic: None,
246        }
247    }
248
249    /// Construct parameters corresponding to `X,Y,Z` accesses, used for vector values.
250    pub fn new_xyz() -> Vec<Self> {
251        vec![
252            Self::new("X", "float"),
253            Self::new("Y", "float"),
254            Self::new("Z", "float"),
255        ]
256    }
257
258    /// Construct parameters corresponding to `S,T` accesses, used for texture coordinates.
259    pub fn new_st() -> Vec<Self> {
260        vec![Self::new("S", "float"), Self::new("T", "float")]
261    }
262}
263
264impl XNode for Param {
265    const NAME: &'static str = "param";
266    fn parse(element: &Element) -> Result<Self> {
267        debug_assert_eq!(element.name(), Self::NAME);
268        Ok(Param {
269            sid: element.attr("sid").map(Into::into),
270            name: element.attr("name").map(Into::into),
271            ty: element.attr("type").ok_or("expecting 'type' attr")?.into(),
272            semantic: parse_attr(element.attr("semantic"))?,
273        })
274    }
275}
276
277impl XNodeWrite for Param {
278    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
279        let mut e = Self::elem();
280        e.opt_attr("sid", &self.sid);
281        e.opt_attr("name", &self.name);
282        e.attr("type", &self.ty);
283        e.opt_print_attr("semantic", &self.semantic);
284        e.end(w)
285    }
286}
287
288/// Declares a data repository that provides values
289/// according to the semantics of an [`Input`] element that refers to it.
290#[derive(Clone, Debug)]
291pub struct Source {
292    /// A text string containing the unique identifier of the element.
293    pub id: Option<String>,
294    /// The text string name of this element.
295    pub name: Option<String>,
296    /// Asset management information about this element.
297    pub asset: Option<Box<Asset>>,
298    /// A data array element.
299    pub array: Option<ArrayElement>,
300    /// The access pattern into the data element.
301    pub accessor: Accessor,
302    /// Declares the information used to process some portion of the content. (optional)
303    pub technique: Vec<Technique>,
304}
305
306impl Source {
307    /// Construct a new `Source` given an inline array and access information.
308    pub fn new_local(
309        id: impl Into<String>,
310        param: Vec<Param>,
311        array: impl Into<ArrayElement>,
312    ) -> Self {
313        let id = id.into();
314        let array = array.into();
315        assert!(!param.is_empty());
316        let count = array.len() / param.len();
317        assert!(param.len() * count == array.len());
318        Self {
319            accessor: Accessor::new(
320                Url::Fragment(array.id().expect("array requires id").into()),
321                count,
322                param,
323            ),
324            id: Some(id),
325            name: None,
326            asset: None,
327            array: Some(array),
328            technique: vec![],
329        }
330    }
331}
332
333impl XNode for Source {
334    const NAME: &'static str = "source";
335    fn parse(element: &Element) -> Result<Self> {
336        debug_assert_eq!(element.name(), Self::NAME);
337        let mut it = element.children().peekable();
338        let res = Source {
339            id: element.attr("id").map(Into::into),
340            name: element.attr("name").map(Into::into),
341            asset: Asset::parse_opt_box(&mut it)?,
342            array: parse_opt_many(&mut it, ArrayElement::parse)?,
343            accessor: parse_one(Technique::COMMON, &mut it, |e| {
344                let mut it = e.children().peekable();
345                finish(Accessor::parse_one(&mut it)?, it)
346            })?,
347            technique: Technique::parse_list(&mut it)?,
348        };
349        if let Some(arr) = &res.array {
350            if arr.len() < res.accessor.offset + res.accessor.stride * res.accessor.count {
351                return Err("array is too short for accessor".into());
352            }
353        }
354        finish(res, it)
355    }
356}
357
358impl XNodeWrite for Source {
359    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
360        let mut e = Self::elem();
361        e.opt_attr("id", &self.id);
362        e.opt_attr("name", &self.name);
363        let e = e.start(w)?;
364        self.asset.write_to(w)?;
365        self.array.write_to(w)?;
366        let common = ElemBuilder::new(Technique::COMMON).start(w)?;
367        self.accessor.write_to(w)?;
368        common.end(w)?;
369        self.technique.write_to(w)?;
370        e.end(w)
371    }
372}
373
374impl CollectLocalMaps for Source {
375    fn collect_local_maps<'a>(&'a self, maps: &mut LocalMaps<'a>) {
376        maps.insert(self);
377        self.array.collect_local_maps(maps);
378    }
379}
380
381impl Traversable for Source {
382    fn traverse<'a, E>(
383        doc: &'a Document,
384        mut f: impl FnMut(&'a Self) -> Result<(), E>,
385    ) -> Result<(), E>
386    where
387        Self: 'a,
388    {
389        doc.library.iter().try_for_each(|elem| match elem {
390            LibraryElement::Animations(lib) => lib
391                .items
392                .iter()
393                .try_for_each(|anim| anim.source.iter().try_for_each(&mut f)),
394            LibraryElement::Controllers(lib) => lib
395                .items
396                .iter()
397                .try_for_each(|con| con.element.sources().iter().try_for_each(&mut f)),
398            LibraryElement::Geometries(lib) => lib
399                .items
400                .iter()
401                .try_for_each(|geom| geom.element.sources().iter().try_for_each(&mut f)),
402            _ => Ok(()),
403        })
404    }
405}
406
407/// Declares the input semantics of a data source and connects a consumer to that source.
408/// In the COLLADA spec this is called "`<input>` (unshared)".
409#[derive(Clone, Debug)]
410pub struct Input {
411    /// The user-defined meaning of the input connection.
412    pub semantic: Semantic,
413    /// The location of the data source.
414    /// The type referenced here depends on the `semantic`:
415    /// * For [`Semantic::Vertex`] it references a [`Vertices`]
416    /// * For most other semantics it references a [`Source`]
417    pub source: Url,
418}
419
420impl XNode for Input {
421    const NAME: &'static str = "input";
422    fn parse(element: &Element) -> Result<Self> {
423        debug_assert_eq!(element.name(), Self::NAME);
424        Ok(Input {
425            semantic: parse_attr(element.attr("semantic"))?.ok_or("missing semantic attr")?,
426            source: parse_attr(element.attr("source"))?.ok_or("missing source attr")?,
427        })
428    }
429}
430
431impl XNodeWrite for Input {
432    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
433        let mut e = Self::elem();
434        e.print_attr("semantic", &self.semantic);
435        e.print_attr("source", &self.source);
436        e.end(w)
437    }
438}
439
440impl Input {
441    /// Construct a new [`Input`].
442    pub fn new(semantic: Semantic, source: Url) -> Self {
443        Self { semantic, source }
444    }
445
446    /// Typecast `self.source` as a `UrlRef<Source>`.
447    /// The `semantic` is checked in debug mode to ensure that it is compatible with a
448    /// [`Source`] target.
449    pub fn source_as_source(&self) -> &UrlRef<Source> {
450        debug_assert!(!matches!(self.semantic, Semantic::Vertex));
451        ref_cast::RefCast::ref_cast(&self.source)
452    }
453
454    /// Typecast `self.source` as a `UrlRef<Vertices>`.
455    /// The `semantic` is checked in debug mode to ensure that it is compatible with a
456    /// [`Vertices`] target.
457    pub fn source_as_vertices(&self) -> &UrlRef<Vertices> {
458        debug_assert!(matches!(self.semantic, Semantic::Vertex));
459        ref_cast::RefCast::ref_cast(&self.source)
460    }
461}
462
463/// Declares the input semantics of a data source and connects a consumer to that source.
464/// In the COLLADA spec this is called "`<input>` (shared)".
465#[derive(Clone, Debug)]
466pub struct InputS {
467    /// [`InputS`] inherits from [`Input`].
468    pub input: Input,
469    /// The offset into the list of indices defined by the parent element’s `prim` field.
470    /// If two [`InputS`] elements share the same offset, they are indexed the same.
471    /// This is a simple form of compression for the list of indices
472    /// and also defines the order in which the inputs are used.
473    pub offset: u32,
474    /// Which inputs to group as a single set. This is helpful when multiple inputs
475    /// share the same semantics.
476    pub set: Option<u32>,
477}
478
479impl InputS {
480    /// Construct a new [`InputS`].
481    pub fn new(semantic: Semantic, source: Url, offset: u32, set: Option<u32>) -> Self {
482        Self {
483            input: Input { semantic, source },
484            offset,
485            set,
486        }
487    }
488}
489
490impl Deref for InputS {
491    type Target = Input;
492    fn deref(&self) -> &Self::Target {
493        &self.input
494    }
495}
496
497impl XNode for InputS {
498    const NAME: &'static str = "input";
499    fn parse(element: &Element) -> Result<Self> {
500        Ok(InputS {
501            input: Input::parse(element)?,
502            offset: parse_attr(element.attr("offset"))?.ok_or("missing offset attr")?,
503            set: parse_attr(element.attr("set"))?,
504        })
505    }
506}
507
508impl XNodeWrite for InputS {
509    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
510        let mut e = Self::elem();
511        e.print_attr("semantic", &self.semantic);
512        e.print_attr("source", &self.source);
513        e.print_attr("offset", self.offset);
514        e.opt_print_attr("set", &self.set);
515        e.end(w)
516    }
517}
518
519/// Wraps a group of inputs and precalculates the `depth` field.
520#[derive(Clone, Default, Debug)]
521pub struct InputList {
522    /// The list of inputs.
523    pub inputs: Vec<InputS>,
524    /// The stride of an input list is the largest offset plus one;
525    /// this is the stride of accesses applied by these inputs.
526    pub stride: usize,
527}
528
529impl Deref for InputList {
530    type Target = Vec<InputS>;
531
532    fn deref(&self) -> &Self::Target {
533        &self.inputs
534    }
535}
536
537impl From<Vec<InputS>> for InputList {
538    fn from(inputs: Vec<InputS>) -> Self {
539        Self::new(inputs)
540    }
541}
542
543impl InputList {
544    /// Construct a new `InputList` from a list of inputs.
545    pub fn new(inputs: Vec<InputS>) -> Self {
546        let stride = inputs.iter().map(|i| i.offset).max().map_or(0, |n| n + 1) as usize;
547        Self { inputs, stride }
548    }
549
550    pub(crate) fn parse<const N: usize>(it: &mut ElementIter<'_>) -> Result<Self> {
551        Ok(InputList::new(InputS::parse_list_n::<N>(it)?))
552    }
553
554    pub(crate) fn check_prim<const MIN: usize>(&self, data: &[u32]) -> bool {
555        self.stride != 0 && data.len() < self.stride * MIN && data.len() % self.stride == 0
556    }
557}
558
559mk_extensible_enum! {
560  /// An [`Input`] semantic attribute. Common / defined values are pre-parsed,
561  /// and the remainder are in the `Other` variant.
562  pub enum Semantic {
563      /// Geometric binormal (bitangent) vector
564      Binormal = "BINORMAL",
565      /// Color coordinate vector. Color inputs are RGB (float3)
566      Color = "COLOR",
567      /// Continuity constraint at the control vertex (CV)
568      Continuity = "CONTINUITY",
569      /// Raster or MIP-level input
570      Image = "IMAGE",
571      /// Sampler input
572      Input = "INPUT",
573      /// Tangent vector for preceding control point
574      InTangent = "IN_TANGENT",
575      /// Sampler interpolation type
576      Interpolation = "INTERPOLATION",
577      /// Inverse of local-to-world matrix
578      InvBindMatrix = "INV_BIND_MATRIX",
579      /// Skin influence identifier
580      Joint = "JOINT",
581      /// Number of piece-wise linear approximation steps to use for the spline segment that
582      /// follows this CV
583      LinearSteps = "LINEAR_STEPS",
584      /// Morph targets for mesh morphing
585      MorphTarget = "MORPH_TARGET",
586      /// Weights for mesh morphing
587      MorphWeight = "MORPH_WEIGHT",
588      /// Normal vector
589      Normal = "NORMAL",
590      /// Sampler output
591      Output = "OUTPUT",
592      /// Tangent vector for succeeding control point
593      OutTangent = "OUT_TANGENT",
594      /// Geometric coordinate vector
595      Position = "POSITION",
596      /// Geometric tangent vector
597      Tangent = "TANGENT",
598      /// Texture binormal (bitangent) vector
599      TexBinormal = "TEXBINORMAL",
600      /// Texture coordinate vector
601      TexCoord = "TEXCOORD",
602      /// Texture coordinate vector
603      TexTangent = "TEXTANGENT",
604      /// Generic parameter vector
605      UV = "UV",
606      /// Mesh vertex
607      Vertex = "VERTEX",
608      /// Skin influence weighting value
609      Weight = "WEIGHT",
610  }
611}