fbx_dom/objects/
animation_stack.rs1use std::collections::HashMap;
7use std::convert::TryFrom;
8
9use crate::Property;
10use crate::{OwnedDocument, OwnedObject};
11
12use super::{AnimationLayer, FbxObjectTag, FbxTypeMismatch, fbx_object_tag};
13
14#[derive(Debug, PartialEq)]
15pub struct AnimationStack(pub OwnedObject);
16
17impl AnimationStack {
18 pub fn inner(&self) -> &OwnedObject {
19 &self.0
20 }
21
22 pub fn into_inner(self) -> OwnedObject {
23 self.0
24 }
25
26 pub fn properties(&self) -> &HashMap<String, Property> {
27 &self.0.properties
28 }
29
30 pub fn property(&self, name: &str) -> Option<&Property> {
31 self.0.properties.get(name)
32 }
33
34 pub fn local_start(&self) -> i64 {
35 match self.property("LocalStart") {
36 Some(Property::ILongLong(v)) => *v,
37 _ => 0,
38 }
39 }
40
41 pub fn local_stop(&self) -> i64 {
42 match self.property("LocalStop") {
43 Some(Property::ILongLong(v)) => *v,
44 _ => 0,
45 }
46 }
47
48 pub fn reference_start(&self) -> i64 {
49 match self.property("ReferenceStart") {
50 Some(Property::ILongLong(v)) => *v,
51 _ => 0,
52 }
53 }
54
55 pub fn reference_stop(&self) -> i64 {
56 match self.property("ReferenceStop") {
57 Some(Property::ILongLong(v)) => *v,
58 _ => 0,
59 }
60 }
61
62 pub fn get_animation_layers<'a>(
64 &'a self,
65 document: &'a OwnedDocument,
66 ) -> Vec<&'a AnimationLayer> {
67 let stack_id = self.inner().object_index;
68 document
69 .animation_layers
70 .iter()
71 .filter(|layer| layer.inner().connected_object_ids.contains(&stack_id))
72 .collect()
73 }
74}
75
76impl TryFrom<OwnedObject> for AnimationStack {
77 type Error = FbxTypeMismatch;
78
79 fn try_from(o: OwnedObject) -> Result<Self, Self::Error> {
80 match fbx_object_tag(&o) {
81 FbxObjectTag::AnimationStack => Ok(AnimationStack(o)),
82 _ => Err(FbxTypeMismatch::wrong_object_kind(
83 o,
84 "AnimationStack".to_string(),
85 )),
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use std::collections::HashMap;
93 use std::convert::TryFrom;
94
95 use crate::objects::{
96 ANIMATION_LAYER_CLASS_NAME, ANIMATION_LAYER_TYPE_NAME, ANIMATION_STACK_CLASS_NAME,
97 ANIMATION_STACK_TYPE_NAME, AnimationLayer,
98 };
99 use crate::{OwnedDocument, OwnedObject, Property};
100
101 use super::AnimationStack;
102
103 #[test]
104 fn stack_time_defaults_and_properties() {
105 let o_empty = OwnedObject {
106 object_index: 5,
107 name: "AnimStack::Take001".into(),
108 type_name: ANIMATION_STACK_TYPE_NAME.into(),
109 class_name: ANIMATION_STACK_CLASS_NAME.into(),
110 properties: HashMap::new(),
111 attributes: HashMap::new(),
112 connected_object_ids: vec![],
113 object_property_targets: vec![],
114 pp_property_targets: HashMap::new(),
115 };
116 let s = AnimationStack::try_from(o_empty).unwrap();
117 assert_eq!(s.local_start(), 0);
118 assert_eq!(s.local_stop(), 0);
119 assert_eq!(s.reference_start(), 0);
120 assert_eq!(s.reference_stop(), 0);
121
122 let mut properties = HashMap::new();
123 properties.insert("LocalStart".to_string(), Property::ILongLong(10));
124 properties.insert("LocalStop".to_string(), Property::ILongLong(100));
125 properties.insert("ReferenceStart".to_string(), Property::ILongLong(20));
126 properties.insert("ReferenceStop".to_string(), Property::ILongLong(200));
127 let o = OwnedObject {
128 object_index: 6,
129 name: "AnimStack::Take002".into(),
130 type_name: ANIMATION_STACK_TYPE_NAME.into(),
131 class_name: ANIMATION_STACK_CLASS_NAME.into(),
132 properties,
133 attributes: HashMap::new(),
134 connected_object_ids: vec![],
135 object_property_targets: vec![],
136 pp_property_targets: HashMap::new(),
137 };
138 let s = AnimationStack::try_from(o).unwrap();
139 assert_eq!(s.local_start(), 10);
140 assert_eq!(s.local_stop(), 100);
141 assert_eq!(s.reference_start(), 20);
142 assert_eq!(s.reference_stop(), 200);
143 }
144
145 #[test]
146 fn resolves_animation_layer_links() {
147 let stack = AnimationStack::try_from(OwnedObject {
148 object_index: 1000,
149 name: "AnimStack::Main".into(),
150 type_name: ANIMATION_STACK_TYPE_NAME.into(),
151 class_name: ANIMATION_STACK_CLASS_NAME.into(),
152 properties: HashMap::new(),
153 attributes: HashMap::new(),
154 connected_object_ids: vec![],
155 object_property_targets: vec![],
156 pp_property_targets: HashMap::new(),
157 })
158 .unwrap();
159 let layer = AnimationLayer::try_from(OwnedObject {
160 object_index: 1001,
161 name: "AnimLayer::Layer0".into(),
162 type_name: ANIMATION_LAYER_TYPE_NAME.into(),
163 class_name: ANIMATION_LAYER_CLASS_NAME.into(),
164 properties: HashMap::new(),
165 attributes: HashMap::new(),
166 connected_object_ids: vec![1000],
167 object_property_targets: vec![],
168 pp_property_targets: HashMap::new(),
169 })
170 .unwrap();
171 let mut owned = OwnedDocument::default();
172 owned.animation_layers = vec![layer];
173 let links = stack.get_animation_layers(&owned);
174 assert_eq!(links.len(), 1);
175 assert_eq!(links[0].inner().object_index, 1001);
176 }
177}