Skip to main content

fbx_dom/objects/
blend_shape.rs

1//! FBX `Deformer` / `BlendShape` — Assimp [`BlendShape`](https://github.com/assimp/assimp/blob/master/code/AssetLib/FBX/FBXDocument.h).
2
3use std::collections::HashMap;
4use std::convert::TryFrom;
5
6use crate::{OwnedDocument, OwnedObject, Property};
7
8use super::{BlendShapeChannel, FbxObjectTag, FbxTypeMismatch, fbx_object_tag};
9
10#[derive(Debug, PartialEq)]
11pub struct BlendShape(pub OwnedObject);
12
13impl BlendShape {
14    pub fn inner(&self) -> &OwnedObject {
15        &self.0
16    }
17
18    pub fn into_inner(self) -> OwnedObject {
19        self.0
20    }
21
22    pub fn properties(&self) -> &HashMap<String, Property> {
23        &self.0.properties
24    }
25
26    pub fn property(&self, name: &str) -> Option<&Property> {
27        self.0.properties.get(name)
28    }
29
30    /// Resolve `BlendShapeChannel -> BlendShape` links via owned OO connections.
31    pub fn get_blend_shape_channels<'a>(
32        &'a self,
33        document: &'a OwnedDocument,
34    ) -> Vec<&'a BlendShapeChannel> {
35        let blend_shape_id = self.inner().object_index;
36        document
37            .blend_shape_channels
38            .iter()
39            .filter(|channel| {
40                channel
41                    .inner()
42                    .connected_object_ids
43                    .contains(&blend_shape_id)
44            })
45            .collect()
46    }
47}
48
49impl TryFrom<OwnedObject> for BlendShape {
50    type Error = FbxTypeMismatch;
51
52    fn try_from(o: OwnedObject) -> Result<Self, Self::Error> {
53        match fbx_object_tag(&o) {
54            FbxObjectTag::BlendShape => Ok(BlendShape(o)),
55            _ => Err(FbxTypeMismatch::wrong_object_kind(
56                o,
57                "BlendShape".to_string(),
58            )),
59        }
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use std::collections::HashMap;
66    use std::convert::TryFrom;
67
68    use crate::objects::{
69        BlendShapeChannel, DEFORMER_BLEND_SHAPE_CHANNEL_CLASS_NAME,
70        DEFORMER_BLEND_SHAPE_CLASS_NAME, DEFORMER_TYPE_NAME,
71    };
72    use crate::{OwnedDocument, OwnedObject, Property};
73
74    use super::BlendShape;
75
76    #[test]
77    fn property_accessors() {
78        let mut properties = HashMap::new();
79        properties.insert("Foo".into(), Property::Int(7));
80        let o = OwnedObject {
81            object_index: 15,
82            name: "BlendShape::A".into(),
83            type_name: DEFORMER_TYPE_NAME.into(),
84            class_name: DEFORMER_BLEND_SHAPE_CLASS_NAME.into(),
85            properties,
86            attributes: HashMap::new(),
87            connected_object_ids: vec![],
88            object_property_targets: vec![],
89            pp_property_targets: HashMap::new(),
90        };
91        let b = BlendShape::try_from(o).unwrap();
92        assert_eq!(b.property("Foo"), Some(&Property::Int(7)));
93    }
94
95    #[test]
96    fn resolves_blend_shape_channel_connections() {
97        let blend_shape = BlendShape::try_from(OwnedObject {
98            object_index: 50,
99            name: "BlendShape::B".into(),
100            type_name: DEFORMER_TYPE_NAME.into(),
101            class_name: DEFORMER_BLEND_SHAPE_CLASS_NAME.into(),
102            properties: HashMap::new(),
103            attributes: HashMap::new(),
104            connected_object_ids: vec![],
105            object_property_targets: vec![],
106            pp_property_targets: HashMap::new(),
107        })
108        .unwrap();
109        let channel = BlendShapeChannel::try_from(OwnedObject {
110            object_index: 51,
111            name: "BlendShapeChannel::B".into(),
112            type_name: DEFORMER_TYPE_NAME.into(),
113            class_name: DEFORMER_BLEND_SHAPE_CHANNEL_CLASS_NAME.into(),
114            properties: HashMap::new(),
115            attributes: HashMap::new(),
116            connected_object_ids: vec![50],
117            object_property_targets: vec![],
118            pp_property_targets: HashMap::new(),
119        })
120        .unwrap();
121
122        let mut owned = OwnedDocument::default();
123        owned.blend_shape_channels = vec![channel];
124        let linked = blend_shape.get_blend_shape_channels(&owned);
125        assert_eq!(linked.len(), 1);
126        assert_eq!(linked[0].inner().object_index, 51);
127    }
128}