fbx_dom/objects/
layered_texture.rs1use std::convert::TryFrom;
4
5use crate::{OwnedDocument, OwnedObject};
6
7use super::{AttrExtractorExt, FbxObjectTag, FbxTypeMismatch, Texture, fbx_object_tag};
8
9const BLEND_MODES_ATTR: &str = "BlendModes";
10const ALPHAS_ATTR: &str = "Alphas";
11
12#[derive(Debug, PartialEq)]
13pub struct LayeredTexture {
14 object: OwnedObject,
15 pub blend_mode: i32,
16 pub alpha: f32,
17}
18
19impl LayeredTexture {
20 pub fn inner(&self) -> &OwnedObject {
21 &self.object
22 }
23
24 pub fn into_inner(self) -> OwnedObject {
25 self.object
26 }
27
28 pub fn blend_mode(&self) -> i32 {
29 self.blend_mode
30 }
31
32 pub fn alpha(&self) -> f32 {
33 self.alpha
34 }
35
36 pub fn get_textures<'a>(&'a self, document: &'a OwnedDocument) -> Vec<&'a Texture> {
38 let layered_texture_id = self.inner().object_index;
39 document
40 .textures
41 .iter()
42 .filter(|texture| {
43 texture
44 .inner()
45 .connected_object_ids
46 .contains(&layered_texture_id)
47 })
48 .collect()
49 }
50
51 pub fn texture_count(&self, document: &OwnedDocument) -> usize {
52 self.get_textures(document).len()
53 }
54}
55
56impl TryFrom<OwnedObject> for LayeredTexture {
57 type Error = FbxTypeMismatch;
58
59 fn try_from(o: OwnedObject) -> Result<Self, Self::Error> {
60 match fbx_object_tag(&o) {
61 FbxObjectTag::LayeredTexture => {
62 let blend_mode = match o
63 .attributes
64 .optional_token_case_insensitive(BLEND_MODES_ATTR)
65 {
66 Ok(v) => v.and_then(|x| x.trim().parse::<i32>().ok()).unwrap_or(0),
67 Err(reason) => return Err(FbxTypeMismatch { object: o, reason }),
68 };
69 let alpha = match o.attributes.optional_token_case_insensitive(ALPHAS_ATTR) {
70 Ok(v) => v.and_then(|x| x.trim().parse::<f32>().ok()).unwrap_or(1.0),
71 Err(reason) => return Err(FbxTypeMismatch { object: o, reason }),
72 };
73 Ok(LayeredTexture {
74 object: o,
75 blend_mode,
76 alpha,
77 })
78 }
79 _ => Err(FbxTypeMismatch::wrong_object_kind(
80 o,
81 "LayeredTexture".to_string(),
82 )),
83 }
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use std::collections::HashMap;
90 use std::convert::TryFrom;
91
92 use fbxscii::{ElementAttribute, LeafAttribute};
93
94 use super::*;
95 use crate::Property;
96 use crate::objects::{
97 LAYERED_TEXTURE_CLASS_NAME, LAYERED_TEXTURE_TYPE_NAME, TEXTURE_CLASS_NAME,
98 TEXTURE_TYPE_NAME,
99 };
100
101 fn leaf(tokens: &[&str]) -> ElementAttribute {
102 ElementAttribute::Leaf(Box::new(LeafAttribute {
103 key: String::new(),
104 tokens: tokens.iter().map(|s| (*s).to_string()).collect(),
105 }))
106 }
107
108 #[test]
109 fn parses_blend_mode_and_alpha() {
110 let layered = LayeredTexture::try_from(OwnedObject {
111 object_index: 900,
112 name: "LayeredTexture::A".into(),
113 type_name: LAYERED_TEXTURE_TYPE_NAME.into(),
114 class_name: LAYERED_TEXTURE_CLASS_NAME.into(),
115 properties: HashMap::new(),
116 attributes: HashMap::from([
117 (BLEND_MODES_ATTR.to_string(), leaf(&["1"])),
118 (ALPHAS_ATTR.to_string(), leaf(&["0.25"])),
119 ]),
120 connected_object_ids: vec![],
121 object_property_targets: vec![],
122 pp_property_targets: HashMap::new(),
123 })
124 .unwrap();
125 assert_eq!(layered.blend_mode(), 1);
126 assert_eq!(layered.alpha(), 0.25);
127 }
128
129 #[test]
130 fn defaults_blend_mode_and_alpha() {
131 let layered = LayeredTexture::try_from(OwnedObject {
132 object_index: 901,
133 name: "LayeredTexture::B".into(),
134 type_name: LAYERED_TEXTURE_TYPE_NAME.into(),
135 class_name: LAYERED_TEXTURE_CLASS_NAME.into(),
136 properties: HashMap::new(),
137 attributes: HashMap::new(),
138 connected_object_ids: vec![],
139 object_property_targets: vec![],
140 pp_property_targets: HashMap::new(),
141 })
142 .unwrap();
143 assert_eq!(layered.blend_mode(), 0);
144 assert_eq!(layered.alpha(), 1.0);
145 }
146
147 #[test]
148 fn resolves_textures_and_count() {
149 let layered = LayeredTexture::try_from(OwnedObject {
150 object_index: 902,
151 name: "LayeredTexture::C".into(),
152 type_name: LAYERED_TEXTURE_TYPE_NAME.into(),
153 class_name: LAYERED_TEXTURE_CLASS_NAME.into(),
154 properties: HashMap::new(),
155 attributes: HashMap::new(),
156 connected_object_ids: vec![],
157 object_property_targets: vec![],
158 pp_property_targets: HashMap::new(),
159 })
160 .unwrap();
161 let texture = Texture::try_from(OwnedObject {
162 object_index: 903,
163 name: "Texture::A".into(),
164 type_name: TEXTURE_TYPE_NAME.into(),
165 class_name: TEXTURE_CLASS_NAME.into(),
166 properties: HashMap::from([("Foo".into(), Property::Int(1))]),
167 attributes: HashMap::new(),
168 connected_object_ids: vec![902],
169 object_property_targets: vec![],
170 pp_property_targets: HashMap::new(),
171 })
172 .unwrap();
173 let mut owned = OwnedDocument::default();
174 owned.textures = vec![texture];
175 let links = layered.get_textures(&owned);
176 assert_eq!(links.len(), 1);
177 assert_eq!(links[0].inner().object_index, 903);
178 assert_eq!(layered.texture_count(&owned), 1);
179 }
180}