1use fbxcel::tree::any::AnyTree;
17use fbxscii::{ElementAmphitheatre, ElementParseError, Parser, ParserError};
18use std::{
19 collections::HashMap,
20 fmt::{Display, Formatter, Result as FmtResult},
21 io::{BufRead, Read, Seek},
22 result::Result,
23};
24
25use crate::{Object, global::GlobalSettings, object::Objects};
26
27#[derive(Debug, PartialEq)]
28pub enum DocumentParseError {
29 ParserError(ParserError),
30 BinaryParserError(String),
31 UnsupportedVersion(u32, Option<String>),
32 RequiredElementNotFound(String),
33 ElementParseError(ElementParseError),
34 PropertyParseError(PropertyParseError),
35}
36
37#[derive(Debug, Default)]
38pub struct ImportSettings {
39 pub strict: bool,
40}
41
42#[derive(Debug, PartialEq, Clone)]
43pub enum Property {
44 String(String),
45 Bool(bool),
46 Int(i32),
47 Float(f32),
48 ULongLong(u64),
49 ILongLong(i64),
50 Vec3([f32; 3]),
51 Vec4([f32; 4]),
52}
53
54#[derive(Debug)]
55pub struct PropertyDetails {
56 pub name: String,
57 pub property: Property,
58}
59
60#[derive(Debug, PartialEq)]
61pub enum PropertyParseError {
62 InvalidTokenLength(usize, Option<String>),
63 MissingPropertyType(String),
64 TokenParseError(String, String),
65}
66
67impl Display for PropertyParseError {
68 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
69 match self {
70 PropertyParseError::InvalidTokenLength(len, property_type) => write!(
71 f,
72 "Invalid token length: {} for property type: {}",
73 len,
74 property_type.as_ref().unwrap_or(&String::new())
75 ),
76 PropertyParseError::MissingPropertyType(property_type) => {
77 write!(f, "Missing property type: {}", property_type)
78 }
79 PropertyParseError::TokenParseError(property_type, token) => write!(
80 f,
81 "Token parse does not match property type: {} for token: {}",
82 property_type, token
83 ),
84 }
85 }
86}
87impl std::error::Error for PropertyParseError {}
88
89pub type Template = HashMap<String, Property>;
90
91#[derive(Debug, PartialEq, Clone)]
92pub struct LazyObject {
93 pub name: String,
94 pub type_name: String,
95 pub class_name: String,
96 pub element_index: usize,
101}
102
103#[derive(Debug, PartialEq, Clone, Hash, Eq)]
109pub struct ObjectPropertyConnection {
110 pub dest: u64,
111 pub property: String,
112}
113
114#[derive(Default, Debug, Clone)]
115pub struct Document {
116 pub(crate) fbx_version: u32,
118 pub(crate) creator: String,
120 pub(crate) creation_date: [u32; 7],
122 pub(crate) templates: HashMap<String, Template>,
124 pub(crate) default_template_by_object_type: HashMap<String, String>,
127 pub(crate) global_settings: Template,
129 pub(crate) object_element_amphitheatre: ElementAmphitheatre,
131 pub(crate) objects: HashMap<u64, LazyObject>,
133 pub(crate) object_connections: HashMap<u64, Vec<u64>>,
135 pub(crate) object_property_connections: HashMap<u64, Vec<ObjectPropertyConnection>>,
137 pub(crate) property_connections:
139 HashMap<ObjectPropertyConnection, Vec<ObjectPropertyConnection>>,
140 pub(crate) object_to_source_properties: HashMap<u64, Vec<String>>,
142}
143
144impl Document {
145 pub fn version(&self) -> u32 {
146 self.fbx_version
147 }
148
149 pub fn creator(&self) -> &str {
150 &self.creator
151 }
152
153 pub fn creation_date(&self) -> &[u32; 7] {
154 &self.creation_date
155 }
156
157 pub fn global_settings(&self) -> GlobalSettings<'_> {
158 GlobalSettings::new(self, &self.global_settings)
159 }
160
161 pub fn objects(&self) -> Objects<'_> {
162 Objects {
163 iter: self.objects.iter(),
164 document: self,
165 }
166 }
167
168 pub fn object_by_index(&self, index: u64) -> Option<Object<'_>> {
169 let object = self.object_for_index(index)?;
170 self.template_for_object(object)
171 .map(|template| Object::new(self, template, object, index))
172 }
173
174 pub(crate) fn object_for_index(&self, index: u64) -> Option<&LazyObject> {
175 self.objects.get(&index)
176 }
177
178 pub(crate) fn template_for_object(&self, object: &LazyObject) -> Option<&Template> {
179 self.templates.get(&object.type_name).or_else(|| {
180 self.default_template_by_object_type
181 .get(&object.type_name)
182 .and_then(|full_key| self.templates.get(full_key))
183 })
184 }
185
186 pub fn from_parser<R>(
187 parser: Parser<R>,
188 settings: ImportSettings,
189 ) -> Result<Self, DocumentParseError>
190 where
191 R: BufRead,
192 {
193 let elements = parser.load().map_err(DocumentParseError::ParserError)?;
194 let mut document = Self::default();
195 elements.load_into_document(&mut document, settings)?;
196 Ok(document)
197 }
198
199 pub fn from_binary_reader<R>(
207 reader: R,
208 settings: ImportSettings,
209 ) -> Result<Self, DocumentParseError>
210 where
211 R: Read + Seek,
212 {
213 let any_tree = AnyTree::from_seekable_reader(reader)
214 .map_err(|error| DocumentParseError::BinaryParserError(error.to_string()))?;
215 let mut document = Self::default();
216 any_tree.load_into_document(&mut document, settings)?;
217 Ok(document)
218 }
219}
220
221pub trait DocumentLoader {
222 fn load_into_document(
223 self,
224 document: &mut Document,
225 settings: ImportSettings,
226 ) -> Result<(), DocumentParseError>;
227}