Skip to main content

russimp_ng/
metadata.rs

1use crate::{sys::*, *};
2use derivative::Derivative;
3
4trait MetaDataEntryCast {
5    fn can_cast(&self) -> bool;
6    fn cast(&self) -> Russult<MetadataType>;
7}
8
9struct MetaDataEntryString<'a> {
10    data: &'a aiMetadataEntry,
11}
12
13struct MetaDataEntryBool<'a> {
14    data: &'a aiMetadataEntry,
15}
16
17struct MetaDataEntryFloat<'a> {
18    data: &'a aiMetadataEntry,
19}
20
21struct MetaDataEntryDouble<'a> {
22    data: &'a aiMetadataEntry,
23}
24
25struct MetaDataEntryInteger<'a> {
26    data: &'a aiMetadataEntry,
27}
28
29struct MetaDataEntryULong<'a> {
30    data: &'a aiMetadataEntry,
31}
32
33impl<'a> MetaDataEntryCast for MetaDataEntryULong<'a> {
34    fn can_cast(&self) -> bool {
35        self.data.mType == aiMetadataType_AI_UINT64
36    }
37
38    fn cast(&self) -> Russult<MetadataType> {
39        let raw = self.data.mData as *mut u64;
40
41        if let Some(result) = unsafe { raw.as_ref() } {
42            return Ok(MetadataType::ULong(*result));
43        }
44
45        Err(RussimpError::MetadataError(
46            "Cant convert to ulong".to_string(),
47        ))
48    }
49}
50
51impl<'a> MetaDataEntryCast for MetaDataEntryInteger<'a> {
52    fn can_cast(&self) -> bool {
53        self.data.mType == aiMetadataType_AI_INT32
54    }
55
56    fn cast(&self) -> Russult<MetadataType> {
57        let raw = self.data.mData as *mut i32;
58
59        if let Some(result) = unsafe { raw.as_ref() } {
60            return Ok(MetadataType::Int(*result));
61        }
62
63        Err(RussimpError::MetadataError(
64            "Cant convert to integer".to_string(),
65        ))
66    }
67}
68
69impl<'a> MetaDataEntryCast for MetaDataEntryBool<'a> {
70    fn can_cast(&self) -> bool {
71        self.data.mType == aiMetadataType_AI_BOOL
72    }
73
74    fn cast(&self) -> Russult<MetadataType> {
75        let raw = self.data.mData as *mut bool;
76
77        if let Some(result) = unsafe { raw.as_ref() } {
78            return Ok(MetadataType::Bool(*result));
79        }
80
81        Err(RussimpError::MetadataError(
82            "Cant convert to bool".to_string(),
83        ))
84    }
85}
86
87impl<'a> MetaDataEntryCast for MetaDataEntryDouble<'a> {
88    fn can_cast(&self) -> bool {
89        self.data.mType == aiMetadataType_AI_DOUBLE
90    }
91
92    fn cast(&self) -> Russult<MetadataType> {
93        let raw = self.data.mData as *mut f64;
94
95        if let Some(result) = unsafe { raw.as_ref() } {
96            return Ok(MetadataType::Double(*result));
97        }
98
99        Err(RussimpError::MetadataError(
100            "Cant convert to double".to_string(),
101        ))
102    }
103}
104
105impl<'a> MetaDataEntryCast for MetaDataEntryFloat<'a> {
106    fn can_cast(&self) -> bool {
107        self.data.mType == aiMetadataType_AI_FLOAT
108    }
109
110    fn cast(&self) -> Russult<MetadataType> {
111        let raw = self.data.mData as *mut f32;
112
113        if let Some(result) = unsafe { raw.as_ref() } {
114            return Ok(MetadataType::Float(*result));
115        }
116
117        Err(RussimpError::MetadataError(
118            "Cant convert to float".to_string(),
119        ))
120    }
121}
122
123impl<'a> MetaDataEntryCast for MetaDataEntryString<'a> {
124    fn can_cast(&self) -> bool {
125        self.data.mType == aiMetadataType_AI_AISTRING
126    }
127
128    fn cast(&self) -> Russult<MetadataType> {
129        let raw = self.data.mData as *const aiString;
130
131        if let Some(result) = unsafe { raw.as_ref() } {
132            Ok(MetadataType::String(result.into()))
133        } else {
134            Err(RussimpError::MetadataError(
135                "Cant convert to string".to_string(),
136            ))
137        }
138    }
139}
140
141struct MetaDataVector3d<'a> {
142    data: &'a aiMetadataEntry,
143}
144
145impl<'a> MetaDataEntryCast for MetaDataVector3d<'a> {
146    fn can_cast(&self) -> bool {
147        self.data.mType == aiMetadataType_AI_AIVECTOR3D
148    }
149
150    fn cast(&self) -> Russult<MetadataType> {
151        let vec: *const aiVector3D = self.data.mData as *const aiVector3D;
152        if let Some(content) = unsafe { vec.as_ref() } {
153            return Ok(MetadataType::Vector3d(content.into()));
154        }
155
156        Err(RussimpError::MetadataError("data is null".to_string()))
157    }
158}
159
160#[derive(Derivative)]
161#[derivative(Debug)]
162pub struct MetaData {
163    pub keys: Vec<String>,
164    pub values: Vec<MetaDataEntry>,
165}
166
167impl From<&aiMetadata> for MetaData {
168    fn from(meta_data: &aiMetadata) -> Self {
169        Self {
170            keys: utils::get_vec(meta_data.mKeys, meta_data.mNumProperties),
171            values: utils::get_vec(meta_data.mValues, meta_data.mNumProperties),
172        }
173    }
174}
175
176#[derive(Derivative, PartialEq)]
177#[derivative(Debug)]
178#[repr(u32)]
179pub enum MetadataType {
180    String(String),
181    Vector3d(Vector3D),
182    Bool(bool),
183    Float(f32),
184    Double(f64),
185    Int(i32),
186    ULong(u64),
187    /* MetaMax = aiMetadataType_AI_META_MAX, -- Not sure what it does
188     * Force32 = aiMetadataType_FORCE_32BIT, -- Not sure what it does */
189}
190
191#[derive(Derivative)]
192#[derivative(Debug)]
193pub struct MetaDataEntry(pub Russult<MetadataType>);
194
195impl MetaDataEntry {
196    fn cast_data(data: &aiMetadataEntry) -> Russult<MetadataType> {
197        let casters: Vec<Box<dyn MetaDataEntryCast>> = vec![
198            Box::new(MetaDataVector3d { data }),
199            Box::new(MetaDataEntryString { data }),
200            Box::new(MetaDataEntryBool { data }),
201            Box::new(MetaDataEntryFloat { data }),
202            Box::new(MetaDataEntryDouble { data }),
203            Box::new(MetaDataEntryInteger { data }),
204            Box::new(MetaDataEntryULong { data }),
205        ];
206
207        for caster in casters {
208            if caster.can_cast() {
209                return caster.cast();
210            }
211        }
212
213        Err(RussimpError::MetadataError(
214            "could not find caster for metadata type".to_string(),
215        ))
216    }
217}
218
219impl From<&aiMetadataEntry> for MetaDataEntry {
220    fn from(data: &aiMetadataEntry) -> Self {
221        Self(Self::cast_data(data))
222    }
223}
224
225#[cfg(test)]
226mod test {
227    use crate::metadata::MetadataType;
228    use crate::utils;
229
230    #[test]
231    fn metadata_for_box() {
232        use crate::scene::{PostProcess, Scene};
233
234        let current_directory_buf = utils::get_model("models/BLEND/box.blend");
235
236        let scene = Scene::from_file(
237            current_directory_buf.as_str(),
238            vec![
239                PostProcess::CalculateTangentSpace,
240                PostProcess::Triangulate,
241                PostProcess::JoinIdenticalVertices,
242                PostProcess::SortByPrimitiveType,
243            ],
244        )
245        .unwrap();
246
247        let metadata = scene.metadata.unwrap();
248
249        assert_eq!(1, metadata.keys.len());
250        assert_eq!(1, metadata.values.len());
251
252        assert_eq!("SourceAsset_Format".to_string(), metadata.keys[0]);
253
254        assert_eq!(
255            metadata.values[0].0.as_ref().unwrap(),
256            &MetadataType::String("Blender 3D Importer (http://www.blender3d.org)".to_string())
257        );
258    }
259
260    #[test]
261    fn debug_metadata() {
262        use crate::scene::{PostProcess, Scene};
263
264        let current_directory_buf = utils::get_model("models/BLEND/box.blend");
265
266        let scene = Scene::from_file(
267            current_directory_buf.as_str(),
268            vec![
269                PostProcess::CalculateTangentSpace,
270                PostProcess::Triangulate,
271                PostProcess::JoinIdenticalVertices,
272                PostProcess::SortByPrimitiveType,
273            ],
274        )
275        .unwrap();
276
277        dbg!(&scene.metadata);
278    }
279}