dae_parser/core/
control.rs

1use crate::*;
2
3/// Categorizes the declaration of generic control information.
4#[derive(Clone, Debug)]
5pub struct Controller {
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 contains control data.
13    pub element: ControlElement,
14    /// Provides arbitrary additional information about this element.
15    pub extra: Vec<Extra>,
16}
17
18impl Controller {
19    /// Create a new [`Controller`] from a [`ControlElement`].
20    pub fn new(element: ControlElement) -> Self {
21        Self {
22            id: None,
23            name: None,
24            asset: None,
25            element,
26            extra: vec![],
27        }
28    }
29}
30
31impl XNode for Controller {
32    const NAME: &'static str = "controller";
33    fn parse(element: &Element) -> Result<Self> {
34        debug_assert_eq!(element.name(), Self::NAME);
35        let mut it = element.children().peekable();
36        Ok(Controller {
37            id: element.attr("id").map(Into::into),
38            name: element.attr("name").map(Into::into),
39            asset: Asset::parse_opt_box(&mut it)?,
40            element: parse_one_many(&mut it, ControlElement::parse)?,
41            extra: Extra::parse_many(it)?,
42        })
43    }
44}
45
46impl XNodeWrite for Controller {
47    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
48        let mut e = Self::elem();
49        e.opt_attr("id", &self.id);
50        e.opt_attr("name", &self.name);
51        let e = e.start(w)?;
52        self.asset.write_to(w)?;
53        self.element.write_to(w)?;
54        self.extra.write_to(w)?;
55        e.end(w)
56    }
57}
58
59/// Extra data associated to [`Instance`]<[`Controller`]>.
60#[derive(Clone, Debug, Default)]
61pub struct InstanceControllerData {
62    /// Indicates where a skin controller is to start to search for the
63    /// joint nodes it needs. This element is meaningless for morph controllers.
64    pub skeleton: Vec<Url>,
65    /// Binds a specific material to a piece of geometry.
66    pub bind_material: Option<BindMaterial>,
67}
68
69impl XNodeWrite for InstanceControllerData {
70    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
71        many(&self.skeleton, |e| ElemBuilder::print("skeleton", e, w))?;
72        self.bind_material.write_to(w)
73    }
74}
75
76impl Instantiate for Controller {
77    const INSTANCE: &'static str = "instance_controller";
78    type Data = InstanceControllerData;
79    fn parse_data(_: &Element, it: &mut ElementIter<'_>) -> Result<Self::Data> {
80        Ok(InstanceControllerData {
81            skeleton: parse_list("skeleton", it, parse_elem)?,
82            bind_material: BindMaterial::parse_opt(it)?,
83        })
84    }
85    fn is_empty(data: &Self::Data) -> bool {
86        data.skeleton.is_empty() && data.bind_material.is_none()
87    }
88}
89
90/// The element that contains control data.
91#[derive(Clone, Debug)]
92pub enum ControlElement {
93    /// Control data for blend-weight skinning.
94    Skin(Skin),
95    /// Control data for blending between sets of static meshes.
96    Morph(Morph),
97}
98
99impl ControlElement {
100    /// Parse a [`ControlElement`] from an XML element.
101    pub fn parse(e: &Element) -> Result<Option<Self>> {
102        match e.name() {
103            Skin::NAME => Ok(Some(Self::Skin(Skin::parse(e)?))),
104            Morph::NAME => Ok(Some(Self::Morph(Morph::parse(e)?))),
105            _ => Ok(None),
106        }
107    }
108
109    /// The `source` URL field on this element.
110    pub fn source(&self) -> &Url {
111        match self {
112            ControlElement::Skin(skin) => &skin.source,
113            ControlElement::Morph(morph) => &morph.source,
114        }
115    }
116
117    /// The `sources` field, which gives the list of [`Source`] elements on this element.
118    pub fn sources(&self) -> &[Source] {
119        match self {
120            ControlElement::Skin(skin) => &skin.sources,
121            ControlElement::Morph(morph) => &morph.sources,
122        }
123    }
124}
125
126impl XNodeWrite for ControlElement {
127    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
128        match self {
129            Self::Skin(e) => e.write_to(w),
130            Self::Morph(e) => e.write_to(w),
131        }
132    }
133}
134
135/// Declares the association between joint nodes and attribute data.
136#[derive(Clone, Debug)]
137pub struct Joints {
138    /// The interpretation of the [`Source`]s.
139    pub inputs: Vec<Input>,
140    /// The index into `inputs` for the [`Semantic::Joint`] input (which must exist).
141    /// The [`Source`] referenced by this input should contain a [`ArrayElement::Name`]
142    /// that contains `sid`s to identify the joint nodes.
143    /// `sid`s are used instead of [`IdRef`](ArrayElement::IdRef)s to allow a skin controller
144    /// to be instantiated multiple times, where each instance can be animated independently.
145    pub joint: usize,
146    /// Provides arbitrary additional information about this element.
147    pub extra: Vec<Extra>,
148}
149
150impl Joints {
151    /// Construct a new `Joints` from a list of inputs.
152    /// One of the inputs must have [`Semantic::Joint`].
153    pub fn new(inputs: Vec<Input>) -> Self {
154        Self {
155            joint: inputs
156                .iter()
157                .position(|i| i.semantic == Semantic::Joint)
158                .expect("joints: missing JOINT input"),
159            inputs,
160            extra: vec![],
161        }
162    }
163}
164
165impl XNode for Joints {
166    const NAME: &'static str = "joints";
167    fn parse(element: &Element) -> Result<Self> {
168        debug_assert_eq!(element.name(), Self::NAME);
169        let mut it = element.children().peekable();
170        let inputs = Input::parse_list_n::<2>(&mut it)?;
171        Ok(Joints {
172            joint: inputs
173                .iter()
174                .position(|i| i.semantic == Semantic::Joint)
175                .ok_or("joints: missing JOINT input")?,
176            inputs,
177            extra: Extra::parse_many(it)?,
178        })
179    }
180}
181
182impl XNodeWrite for Joints {
183    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
184        let e = Self::elem().start(w)?;
185        self.inputs.write_to(w)?;
186        self.extra.write_to(w)?;
187        e.end(w)
188    }
189}
190
191impl Joints {
192    /// The input with [`Semantic::Joint`].
193    pub fn joint_input(&self) -> &Input {
194        &self.inputs[self.joint]
195    }
196}
197
198/// Describes the data required to blend between sets of static meshes.
199#[derive(Clone, Debug)]
200pub struct Morph {
201    /// Refers to the [`Geometry`] that describes the base mesh.
202    pub source: UrlRef<Geometry>,
203    /// Which blending technique to use.
204    pub method: MorphMethod,
205    /// Data for morph weights and for morph targets.
206    pub sources: Vec<Source>,
207    /// Input meshes (morph targets) to be blended.
208    pub targets: Targets,
209    /// Provides arbitrary additional information about this element.
210    pub extra: Vec<Extra>,
211}
212
213impl Morph {
214    /// Construct a new `Morph` of  from a list of sources and targets.
215    /// * The `source` should reference a `Geometry`.
216    /// * There should be at least two `sources`.
217    /// * One of the `targets` must have [`Semantic::MorphTarget`].
218    /// * One of the `targets` must have [`Semantic::MorphWeight`].
219    pub fn new(source: Url, sources: Vec<Source>, targets: Vec<Input>) -> Self {
220        assert!(sources.len() >= 2);
221        Self {
222            source: Ref::new(source),
223            method: Default::default(),
224            sources,
225            targets: Targets::new(targets),
226            extra: vec![],
227        }
228    }
229}
230
231impl XNode for Morph {
232    const NAME: &'static str = "morph";
233    fn parse(element: &Element) -> Result<Self> {
234        debug_assert_eq!(element.name(), Self::NAME);
235        let mut it = element.children().peekable();
236        Ok(Morph {
237            source: parse_attr(element.attr("source"))?.ok_or("missing source attr")?,
238            method: parse_attr(element.attr("method"))?.unwrap_or_default(),
239            sources: Source::parse_list_n::<2>(&mut it)?,
240            targets: Targets::parse_one(&mut it)?,
241            extra: Extra::parse_many(it)?,
242        })
243    }
244}
245
246impl XNodeWrite for Morph {
247    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
248        let mut e = Self::elem();
249        e.print_attr("source", &self.source);
250        e.print_attr("method", self.method);
251        let e = e.start(w)?;
252        self.sources.write_to(w)?;
253        self.targets.write_to(w)?;
254        self.extra.write_to(w)?;
255        e.end(w)
256    }
257}
258
259/// Which blending technique to use.
260#[derive(Clone, Copy, Debug, PartialEq, Eq)]
261pub enum MorphMethod {
262    /// ```text
263    /// (Target1, Target2, ...)*(w1, w2, ...) =
264    ///     (1-w1-w2-...)*BaseMesh + w1*Target1 + w2*Target2 + ...
265    /// ```
266    Normalized,
267    /// ```text
268    /// (Target1, Target2, ...) + (w1, w2, ...) =
269    ///     BaseMesh + w1*Target1 + w2*Target2 + ...
270    /// ```
271    Relative,
272}
273
274impl Default for MorphMethod {
275    fn default() -> Self {
276        Self::Normalized
277    }
278}
279
280impl FromStr for MorphMethod {
281    type Err = ();
282
283    fn from_str(s: &str) -> Result<Self, Self::Err> {
284        match s {
285            "NORMALIZED" => Ok(Self::Normalized),
286            "RELATIVE" => Ok(Self::Relative),
287            _ => Err(()),
288        }
289    }
290}
291
292impl MorphMethod {
293    /// The XML name of a value in this enumeration.
294    pub fn to_str(self) -> &'static str {
295        match self {
296            Self::Normalized => "NORMALIZED",
297            Self::Relative => "RELATIVE",
298        }
299    }
300}
301
302impl Display for MorphMethod {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        Display::fmt(self.to_str(), f)
305    }
306}
307
308/// Contains vertex and primitive information sufficient to describe blend-weight skinning.
309#[derive(Clone, Debug)]
310pub struct Skin {
311    /// A URI reference to the base mesh (a static mesh or a morphed mesh).
312    /// This also provides the bind-shape of the skinned mesh.
313    pub source: UrlRef<Mesh>,
314    /// Provides extra information about the position and
315    /// orientation of the base mesh before binding. Contains
316    /// sixteen floating-point numbers representing a four-by-
317    /// four matrix in column-major order. If `bind_shape_matrix` is not specified
318    /// then an identity matrix may be used as the `bind_shape_matrix`.
319    pub bind_shape_matrix: Option<Box<[f32; 16]>>,
320    /// Provides most of the data required for skinning the given base mesh.
321    pub sources: Vec<Source>,
322    /// Aggregates the per-joint information needed for this skin.
323    pub joints: Joints,
324    /// Describes a per-vertex combination of joints and
325    /// weights used in this skin. An index of `–1` into the array of
326    /// joints refers to the bind shape. Weights should be
327    /// normalized before use.
328    pub weights: VertexWeights,
329    /// Provides arbitrary additional information about this element.
330    pub extra: Vec<Extra>,
331}
332
333impl Skin {
334    /// Construct a `Skin` from the mandatory data.
335    /// * The source should reference a `Mesh`.
336    /// * There should be at least 3 `sources`.
337    /// * One of the `joints` must have [`Semantic::Joint`].
338    pub fn new(
339        source: Url,
340        sources: Vec<Source>,
341        joints: Vec<Input>,
342        weights: VertexWeights,
343    ) -> Self {
344        assert!(sources.len() >= 3);
345        Self {
346            source: Ref::new(source),
347            bind_shape_matrix: None,
348            sources,
349            joints: Joints::new(joints),
350            weights,
351            extra: vec![],
352        }
353    }
354}
355
356impl XNode for Skin {
357    const NAME: &'static str = "skin";
358    fn parse(element: &Element) -> Result<Self> {
359        debug_assert_eq!(element.name(), Self::NAME);
360        let mut it = element.children().peekable();
361        Ok(Skin {
362            source: parse_attr(element.attr("source"))?.ok_or("missing source attr")?,
363            bind_shape_matrix: parse_opt("bind_shape_matrix", &mut it, parse_array_n)?,
364            sources: Source::parse_list_n::<3>(&mut it)?,
365            joints: Joints::parse_one(&mut it)?,
366            weights: VertexWeights::parse_one(&mut it)?,
367            extra: Extra::parse_many(it)?,
368        })
369    }
370}
371
372impl XNodeWrite for Skin {
373    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
374        let mut e = Self::elem();
375        e.print_attr("source", &self.source);
376        let e = e.start(w)?;
377        opt(&self.bind_shape_matrix, |e| {
378            ElemBuilder::print_arr("bind_shape_matrix", &**e, w)
379        })?;
380        self.sources.write_to(w)?;
381        self.joints.write_to(w)?;
382        self.weights.write_to(w)?;
383        self.extra.write_to(w)?;
384        e.end(w)
385    }
386}
387
388/// Declares morph targets, their weights, and any user-defined attributes associated with them.
389#[derive(Clone, Debug)]
390pub struct Targets {
391    /// The interpretation of the [`Source`]s.
392    pub inputs: Vec<Input>,
393    /// The index into `inputs` for the [`Semantic::MorphTarget`] input (which must exist).
394    pub morph_target: usize,
395    /// The index into `inputs` for the [`Semantic::MorphWeight`] input (which must exist).
396    pub morph_weight: usize,
397    /// Provides arbitrary additional information about this element.
398    pub extra: Vec<Extra>,
399}
400
401impl Targets {
402    /// Construct a new `Targets` from a list of inputs.
403    /// One of the inputs must have [`Semantic::MorphTarget`], and
404    /// one of the inputs must have [`Semantic::MorphWeight`].
405    pub fn new(inputs: Vec<Input>) -> Self {
406        Self {
407            morph_target: inputs
408                .iter()
409                .position(|i| i.semantic == Semantic::MorphTarget)
410                .expect("targets: missing MORPH_TARGET input"),
411            morph_weight: inputs
412                .iter()
413                .position(|i| i.semantic == Semantic::MorphWeight)
414                .expect("targets: missing MORPH_WEIGHT input"),
415            inputs,
416            extra: vec![],
417        }
418    }
419}
420
421impl XNode for Targets {
422    const NAME: &'static str = "targets";
423    fn parse(element: &Element) -> Result<Self> {
424        debug_assert_eq!(element.name(), Self::NAME);
425        let mut it = element.children().peekable();
426        let inputs = Input::parse_list(&mut it)?;
427        Ok(Targets {
428            morph_target: inputs
429                .iter()
430                .position(|i| i.semantic == Semantic::MorphTarget)
431                .ok_or("targets: missing MORPH_TARGET input")?,
432            morph_weight: inputs
433                .iter()
434                .position(|i| i.semantic == Semantic::MorphWeight)
435                .ok_or("targets: missing MORPH_WEIGHT input")?,
436            inputs,
437            extra: Extra::parse_many(it)?,
438        })
439    }
440}
441
442impl XNodeWrite for Targets {
443    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
444        let e = Self::elem().start(w)?;
445        self.inputs.write_to(w)?;
446        self.extra.write_to(w)?;
447        e.end(w)
448    }
449}
450
451impl Targets {
452    /// The input with [`Semantic::MorphTarget`].
453    pub fn morph_target_input(&self) -> &Input {
454        &self.inputs[self.morph_target]
455    }
456
457    /// The input with [`Semantic::MorphWeight`].
458    pub fn morph_weight_input(&self) -> &Input {
459        &self.inputs[self.morph_weight]
460    }
461}
462
463/// Describes the combination of joints and weights used by a skin.
464#[derive(Clone, Debug)]
465pub struct VertexWeights {
466    /// The number of vertices in the base mesh.
467    pub count: usize,
468    /// The [`InputS`] elements describe the joints and the attributes to be associated with them.
469    pub inputs: InputList,
470    /// The index into `inputs` for the [`Semantic::Joint`] input (which must exist).
471    pub joint: usize,
472    /// Contains a list of integers, each specifying the number of
473    /// bones associated with one of the influences defined by [`VertexWeights`].
474    pub vcount: Box<[u32]>,
475    /// Contains a list of indices that describe which bones and
476    /// attributes are associated with each vertex. An index of `-1`
477    /// into the array of joints refers to the bind shape. Weights
478    /// should be normalized before use.
479    pub prim: Box<[i32]>,
480    /// Provides arbitrary additional information about this element.
481    pub extra: Vec<Extra>,
482}
483
484impl XNode for VertexWeights {
485    const NAME: &'static str = "vertex_weights";
486    fn parse(element: &Element) -> Result<Self> {
487        debug_assert_eq!(element.name(), Self::NAME);
488        let mut it = element.children().peekable();
489        let inputs = InputList::parse::<2>(&mut it)?;
490        let res = VertexWeights {
491            count: parse_attr(element.attr("count"))?.ok_or("expected 'count' attr")?,
492            joint: inputs
493                .iter()
494                .position(|i| i.semantic == Semantic::Joint)
495                .ok_or("vertex_weights: missing JOINT input")?,
496            inputs,
497            vcount: parse_opt("vcount", &mut it, parse_array)?.unwrap_or_default(),
498            prim: parse_opt("v", &mut it, parse_array)?.unwrap_or_default(),
499            extra: Extra::parse_many(it)?,
500        };
501        validate_vcount(res.count, res.inputs.stride, &res.vcount, &res.prim)?;
502        Ok(res)
503    }
504}
505
506impl XNodeWrite for VertexWeights {
507    fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
508        let mut e = Self::elem();
509        e.print_attr("count", self.count);
510        let e = e.start(w)?;
511        self.inputs.write_to(w)?;
512        ElemBuilder::print_arr("vcount", &self.vcount, w)?;
513        ElemBuilder::print_arr("v", &self.prim, w)?;
514        self.extra.write_to(w)?;
515        e.end(w)
516    }
517}
518
519impl VertexWeights {
520    /// Construct a new `VertexWeights` from a list of inputs.
521    /// One of the `inputs` must have [`Semantic::Joint`].
522    pub fn new(inputs: Vec<InputS>, vcount: Box<[u32]>, prim: Box<[i32]>) -> Self {
523        let inputs = InputList::new(inputs);
524        assert!(
525            inputs.stride * vcount.iter().sum::<u32>() as usize == prim.len(),
526            "vcount does not match prim"
527        );
528        Self {
529            count: vcount.len(),
530            joint: inputs
531                .iter()
532                .position(|i| i.semantic == Semantic::Joint)
533                .expect("vertex_weights: missing JOINT input"),
534            inputs,
535            vcount,
536            prim,
537            extra: vec![],
538        }
539    }
540
541    /// The input with [`Semantic::Joint`].
542    pub fn joint_input(&self) -> &Input {
543        &self.inputs[self.joint]
544    }
545}