vkobject_rs/
wavefrontobj.rs

1
2use std::{
3	any::Any,
4	cmp::max,
5	collections::{BTreeMap, BTreeSet, HashMap},
6	fmt::{self, Debug, Formatter},
7	fs::File,
8	hash::{Hash, Hasher},
9	io::{self, BufRead, BufReader, ErrorKind},
10	mem::size_of,
11	ops::{Add, Sub, Mul, Div, Rem, Neg, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign},
12	path::{Path, PathBuf},
13	slice,
14	str::FromStr,
15	sync::{Arc, OnceLock, RwLock},
16};
17extern crate nalgebra_glm as glm;
18use glm::*;
19use simba::simd::SimdComplexField;
20
21/// The OBJ error
22#[derive(Debug, Clone)]
23pub enum ObjError {
24	ParseError{line: usize, what: String},
25	IOError{kind: ErrorKind, what: String},
26	MeshIndicesUnderflow,
27	MeshIndicesOverflow,
28	NeedTexCoordAndNormal,
29}
30
31impl From<io::Error> for ObjError {
32	fn from(e: io::Error) -> Self {
33		Self::IOError {
34			kind: e.kind(),
35			what: format!("{e:?}"),
36		}
37	}
38}
39
40/// The index of the OBJ file faces
41#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct ObjVTNIndex {
43	/// Vertex, 0 is illegal
44	pub v: u32,
45
46	/// Texcoord, 0 means no texcoord
47	pub vt: u32,
48
49	/// Normal, 0 means no normal
50	pub vn: u32,
51}
52
53impl ObjVTNIndex {
54	/// Parse the string into a VTN index, the string should be like `1/2/3`
55	pub fn parse(line_number: usize, s: &str) -> Result<Self, ObjError> {
56		let mut parts: Vec<&str> = s.split('/').collect();
57		while parts.len() < 3 {
58			parts.push("");
59		}
60		if parts.len() > 3 {
61			return Err(ObjError::ParseError {
62				line: line_number,
63				what: format!("Unknown line which could be splitted into {} parts: `{s}`", parts.len()),
64			});
65		}
66		let v = parts[0].parse::<u32>().ok().ok_or(ObjError::ParseError {
67			line: line_number,
68			what: format!("Parse vertex index failed from the data `{s}`"),
69		})?;
70		let vt = if parts[1].is_empty() {
71			0
72		} else {
73			parts[1].parse::<u32>().ok().ok_or(ObjError::ParseError {
74				line: line_number,
75				what: format!("Parse texcoord index failed from the data `{s}`"),
76			})?
77		};
78		let vn = if parts[2].is_empty() {
79			0
80		} else {
81			parts[2].parse::<u32>().ok().ok_or(ObjError::ParseError {
82				line: line_number,
83				what: format!("Parse normal index failed from the data `{s}`"),
84			})?
85		};
86		Ok(Self {
87			v,
88			vt,
89			vn,
90		})
91	}
92}
93
94/// The smooth subset of the OBJ file
95#[derive(Default, Debug, Clone)]
96pub struct ObjSmoothGroup {
97	/// The lines of the group
98	pub lines: Vec<Vec<u32>>,
99
100	/// The triangle faces of the group. If the original face is a quad, the quad is broken into 2 triangles
101	pub triangles: Vec<(ObjVTNIndex, ObjVTNIndex, ObjVTNIndex)>,
102}
103
104/// The material subset of the OBJ file
105#[derive(Default, Debug, Clone)]
106pub struct ObjMaterialGroup {
107	/// The optional smooth group of the geometry in bitfields. If the group doesn't provide, its value is 0 means no smoothing.
108	pub smooth_groups: BTreeMap<i32, Arc<RwLock<ObjSmoothGroup>>>,
109}
110
111/// The group subset of the OBJ file
112#[derive(Default, Debug, Clone)]
113pub struct ObjGroups {
114	/// The material groups in the object
115	pub material_groups: BTreeMap<String, ObjMaterialGroup>,
116}
117
118/// The object subset of the OBJ file
119#[derive(Default, Debug, Clone)]
120pub struct ObjObjects {
121	/// The groups in the object
122	pub groups: BTreeMap<String, ObjGroups>,
123}
124
125/// A trait that tells how many operators could be used on a floating number
126pub trait FloatOps: Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self> + Neg<Output = Self> + PartialEq + PartialOrd + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign + Sized + num_traits::identities::Zero + num_traits::Float + SimdComplexField{}
127
128impl FloatOps for f32 {}
129impl FloatOps for f64 {}
130
131/// The trait for `TVecN<>` component type
132pub trait ObjMeshVecCompType: Default + Clone + Copy + Sized + PartialEq + Debug + FromStr + Any + FloatOps {}
133impl<T> ObjMeshVecCompType for T where T: Default + Clone + Copy + Sized + PartialEq + Debug + FromStr + Any + FloatOps {}
134
135/// The trait for indices type
136pub trait ObjMeshIndexType: Default + Clone + Copy + Sized + PartialEq + Eq + TryFrom<usize> + TryInto<usize> + Any + Debug {}
137impl<T> ObjMeshIndexType for T where T: Default + Clone + Copy + Sized + PartialEq + Eq + TryFrom<usize> + TryInto<usize> + Any + Debug {}
138
139#[derive(Default, Debug, Clone, Copy)]
140pub struct ObjVertices<F>
141where
142	F: ObjMeshVecCompType {
143	/// The `v` part of the VTN vertex
144	pub position: TVec3<F>,
145
146	/// The `vt` part of the VTN vertex
147	pub texcoord: Option<TVec3<F>>,
148
149	/// The `vn` part of the VTN vertex
150	pub normal: Option<TVec3<F>>,
151
152	/// The tangent of the vertex, not come from the OBJ mesh
153	pub tangent: Option<TVec3<F>>,
154}
155
156impl<F> ObjVertices<F>
157where
158	F: ObjMeshVecCompType {
159	pub fn slap_flatten(&self) -> Vec<F> {
160		self.position.iter().cloned()
161		.chain(self.texcoord.unwrap_or_default().iter().cloned())
162		.chain(self.normal.unwrap_or_default().iter().cloned())
163		.chain(self.tangent.unwrap_or_default().iter().cloned())
164		.collect()
165	}
166}
167
168impl<F> PartialEq for ObjVertices<F>
169where
170	F: ObjMeshVecCompType {
171    fn eq(&self, other: &Self) -> bool {
172		let self_data = self.slap_flatten();
173		let other_data = other.slap_flatten();
174		let self_bytes = self_data.len() * size_of::<F>();
175		let other_bytes = other_data.len() * size_of::<F>();
176		match size_of::<F>() {
177			1 => unsafe {slice::from_raw_parts(self_data.as_ptr() as *const u8, self_bytes) == slice::from_raw_parts(other_data.as_ptr() as *const u8, other_bytes)},
178			2 => unsafe {slice::from_raw_parts(self_data.as_ptr() as *const u8, self_bytes) == slice::from_raw_parts(other_data.as_ptr() as *const u8, other_bytes)},
179			4 => unsafe {slice::from_raw_parts(self_data.as_ptr() as *const u8, self_bytes) == slice::from_raw_parts(other_data.as_ptr() as *const u8, other_bytes)},
180			8 => unsafe {slice::from_raw_parts(self_data.as_ptr() as *const u8, self_bytes) == slice::from_raw_parts(other_data.as_ptr() as *const u8, other_bytes)},
181			o => panic!("Invalid primitive type of `<F>`, the size of this type is `{o}`"),
182		}
183    }
184}
185
186impl<F> Eq for ObjVertices<F> where F: ObjMeshVecCompType {}
187
188impl<F> Hash for ObjVertices<F>
189where
190	F: ObjMeshVecCompType {
191	fn hash<H: Hasher>(&self, state: &mut H) {
192		let data = self.slap_flatten();
193		match size_of::<F>() {
194			1 => {state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len())});}
195			2 => {state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 2)});}
196			4 => {state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4)});}
197			8 => {state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 8)});}
198			o => panic!("Invalid primitive type of `<F>`, the size of this type is `{o}`"),
199		}
200	}
201}
202
203#[derive(Default, Debug, Clone)]
204pub struct ObjIndexedMesh<E>
205where
206	E: ObjMeshIndexType {
207	/// The object name
208	pub object_name: String,
209
210	/// The group name
211	pub group_name: String,
212
213	/// The material name
214	pub material_name: String,
215
216	/// The smooth group
217	pub smooth_group: i32,
218
219	/// The face indices
220	pub face_indices: Vec<(E, E, E)>,
221
222	/// The line indices
223	pub line_indices: Vec<Vec<E>>,
224}
225
226#[derive(Default, Debug, Clone)]
227pub struct ObjUnindexedMesh<F>
228where
229	F: ObjMeshVecCompType {
230	/// The object name
231	pub object_name: String,
232
233	/// The group name
234	pub group_name: String,
235
236	/// The material name
237	pub material_name: String,
238
239	/// The smooth group
240	pub smooth_group: i32,
241
242	/// The face indices
243	pub faces: Vec<(ObjVertices<F>, ObjVertices<F>, ObjVertices<F>)>,
244
245	/// The line indices
246	pub lines: Vec<Vec<TVec3<F>>>,
247}
248
249#[derive(Default, Debug, Clone)]
250pub struct ObjIndexedMeshSet<F, E>
251where
252	F: ObjMeshVecCompType,
253	E: ObjMeshIndexType {
254	/// The face vertices
255	pub face_vertices: Vec<ObjVertices<F>>,
256
257	/// The line vertices
258	pub line_vertices: Vec<TVec3<F>>,
259
260	/// The meshes
261	pub meshes: Vec<ObjIndexedMesh<E>>,
262}
263
264/// The raw objmesh that's just the intepreted result of a obj file.
265#[derive(Default, Debug, Clone)]
266pub struct ObjMesh<F>
267where
268	F: ObjMeshVecCompType {
269	/// All of the vertices, the `v x y z` lines.
270	pub vertices: Vec<TVec3<F>>,
271
272	/// All of the normals, the `vn x y z` lines.
273	pub normals: Vec<TVec3<F>>,
274
275	/// All of the texture coords, the `vt x y [z]` lines, with the optional `z` component (default to 0.0)
276	pub texcoords: Vec<TVec3<F>>,
277
278	/// The objects of the OBJ file
279	pub objects: BTreeMap<String, ObjObjects>,
280
281	/// The materials of the OBJ file
282	pub materials: BTreeMap<String, Arc<RwLock<dyn ObjMaterial>>>,
283}
284
285/// Trim line and remove comments
286fn concentrate_line(line: &str) -> &str {
287	let line = line.trim_start();
288	let line = if let Some(pos) = line.find('#') {
289		&line[0..pos]
290	} else {
291		line
292	};
293	line.trim_end()
294}
295
296#[derive(Default, Debug, Clone, Copy, PartialEq)]
297struct LineVert<F: ObjMeshVecCompType> {
298	x: F,
299	y: F,
300	z: F,
301}
302
303impl<F> Eq for LineVert<F> where F: ObjMeshVecCompType {}
304
305impl<F> Hash for LineVert<F>
306where F: ObjMeshVecCompType {
307	fn hash<H: Hasher>(&self, state: &mut H) {
308		match size_of::<F>() {
309			1 => {let data: Vec<u8 > = unsafe {vec![*(&self.x as *const F as *const u8 ), *(&self.y as *const F as *const u8 ), *(&self.z as *const F as *const u8 )]}; state.write(unsafe {slice::from_raw_parts(data.as_ptr(), data.len())});}
310			2 => {let data: Vec<u16> = unsafe {vec![*(&self.x as *const F as *const u16), *(&self.y as *const F as *const u16), *(&self.z as *const F as *const u16)]}; state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 2)});}
311			4 => {let data: Vec<u32> = unsafe {vec![*(&self.x as *const F as *const u32), *(&self.y as *const F as *const u32), *(&self.z as *const F as *const u32)]}; state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 4)});}
312			8 => {let data: Vec<u64> = unsafe {vec![*(&self.x as *const F as *const u64), *(&self.y as *const F as *const u64), *(&self.z as *const F as *const u64)]}; state.write(unsafe {slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 8)});}
313			o => panic!("Invalid primitive type of `<F>`, the size of this type is `{o}`"),
314		}
315	}
316}
317
318fn get_face_vert_index<V, E>(face_vertices_map: &mut HashMap<V, E>, face_vert: &V) -> Result<E, ObjError>
319where
320	V: PartialEq + Eq + Hash + Clone + Copy + Sized,
321	E: ObjMeshIndexType {
322	if let Some(index) = face_vertices_map.get(face_vert) {
323		Ok(*index)
324	} else {
325		let new_index = face_vertices_map.len();
326		let new_ret = E::try_from(new_index).map_err(|_| ObjError::MeshIndicesOverflow)?;
327		face_vertices_map.insert(*face_vert, new_ret);
328		Ok(new_ret)
329	}
330}
331
332fn get_line_vert_index<F, E>(line_vertices_map: &mut HashMap<LineVert<F>, E>, line_vert: &TVec3<F>) -> Result<E, ObjError>
333where
334	F: ObjMeshVecCompType,
335	E: ObjMeshIndexType {
336	let line_vert = LineVert {
337		x: line_vert.x,
338		y: line_vert.y,
339		z: line_vert.z,
340	};
341	if let Some(index) = line_vertices_map.get(&line_vert) {
342		Ok(*index)
343	} else {
344		let new_index = line_vertices_map.len();
345		let new_ret = E::try_from(new_index).map_err(|_| ObjError::MeshIndicesOverflow)?;
346		line_vertices_map.insert(line_vert, new_ret);
347		Ok(new_ret)
348	}
349}
350
351impl<F> ObjMesh<F>
352where
353	F: ObjMeshVecCompType {
354	/// Parse an OBJ file.
355	pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self, ObjError> {
356		let reader = BufReader::new(File::open(&path)?);
357		let mut vertices: Vec<TVec3<F>> = Vec::new();
358		let mut normals: Vec<TVec3<F>> = Vec::new();
359		let mut texcoords: Vec<TVec3<F>> = Vec::new();
360		let mut objects: BTreeMap<String, ObjObjects> = BTreeMap::new();
361		let mut materials: BTreeMap<String, Arc<RwLock<dyn ObjMaterial>>> = BTreeMap::new();
362		let mut mat_loader = None;
363		let mut object_name = String::from("");
364		let mut group_name = String::from("");
365		let mut material_name = String::from("");
366		let mut smoothing_group = 0;
367		let mut last_smoothing_group = None;
368		for (line_number, line) in reader.lines().enumerate() {
369			let line = line?;
370			let line = concentrate_line(&line);
371			if line.is_empty() {
372				continue;
373			}
374			if let Some(data) = line.strip_prefix("mtllib ") {
375				let mtllib_fn = data.trim();
376				let mut mtllib_path = PathBuf::from(path.as_ref());
377				mtllib_path.set_file_name(mtllib_fn);
378				match ObjMaterialLoader::from_file(&mtllib_path) {
379					Ok(matlib) => {
380						for (mat_name, mat_data) in matlib.iter() {
381							materials.insert(mat_name.to_string(), mat_data.clone());
382						}
383					}
384					Err(e) => {
385						eprintln!("Parse material library `{mtllib_fn}` from `{}` failed: {e:?}", mtllib_path.display());
386					}
387				}
388				continue;
389			} else if line.starts_with("newmtl ") {
390				if mat_loader.is_none() {
391					mat_loader = Some(ObjMaterialLoader {
392						path: PathBuf::from(path.as_ref()),
393						materials: BTreeMap::new(),
394						cur_material_name: String::default(),
395						cur_material_fields: BTreeMap::new(),
396					});
397				}
398				mat_loader.as_mut().unwrap().process_line(line_number, line)?;
399				continue;
400			} else if let Some(ref mut loader) = mat_loader {
401				match loader.process_line(line_number, line) {
402					Ok(_) => continue,
403					Err(_) => {
404						loader.finish_material();
405						for (mat_name, mat_data) in loader.materials.iter() {
406							materials.insert(mat_name.to_string(), mat_data.clone());
407						}
408						mat_loader = None;
409					}
410				}
411			}
412			if let Some(data) = line.strip_prefix("v ") {
413				let value = data.trim();
414				let mut parts: Vec<&str> = value.split_whitespace().collect();
415				while parts.len() < 3 {
416					parts.push(" 0.0");
417				}
418				let x = parts[0].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[0])})?;
419				let y = parts[1].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[1])})?;
420				let z = parts[2].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[2])})?;
421				vertices.push(TVec3::new(x, y, z));
422			} else if let Some(data) = line.strip_prefix("vt ") {
423				let value = data.trim();
424				let mut parts: Vec<&str> = value.split_whitespace().collect();
425				while parts.len() < 3 {
426					parts.push(" 0.0");
427				}
428				let x = parts[0].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[0])})?;
429				let y = parts[1].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[1])})?;
430				let z = parts[2].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[2])})?;
431				texcoords.push(TVec3::new(x, y, z));
432			} else if let Some(data) = line.strip_prefix("vn ") {
433				let value = data.trim();
434				let mut parts: Vec<&str> = value.split_whitespace().collect();
435				while parts.len() < 3 {
436					parts.push(" 0.0");
437				}
438				let x = parts[0].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[0])})?;
439				let y = parts[1].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[1])})?;
440				let z = parts[2].parse::<F>().ok().ok_or(ObjError::ParseError {line: line_number, what: format!("Could not parse `{}`", parts[2])})?;
441				normals.push(TVec3::new(x, y, z));
442			} else if line.starts_with("f ") || line.starts_with("l ") {
443				let value = line["f ".len()..].trim();
444				let parts: Vec<&str> = value.split_whitespace().collect();
445				if parts.len() < 3 {
446					eprintln!("Parse line `{line_number}` error: `{line}`: Insufficient index count for a face.");
447					continue;
448				}
449				if last_smoothing_group.is_none() {
450					let object = if let Some(object) = objects.get_mut(&object_name) {
451						object
452					} else {
453						objects.insert(object_name.clone(), ObjObjects::default());
454						objects.get_mut(&object_name).unwrap()
455					};
456					let group = if let Some(group) = object.groups.get_mut(&group_name) {
457						group
458					} else {
459						object.groups.insert(group_name.clone(), ObjGroups::default());
460						object.groups.get_mut(&group_name).unwrap()
461					};
462					let matgroup = if let Some(matgroup) = group.material_groups.get_mut(&material_name) {
463						matgroup
464					} else {
465						group.material_groups.insert(material_name.clone(), ObjMaterialGroup::default());
466						group.material_groups.get_mut(&material_name).unwrap()
467					};
468					let smthgroup = if let Some(smthgroup) = matgroup.smooth_groups.get_mut(&smoothing_group) {
469						smthgroup
470					} else {
471						matgroup.smooth_groups.insert(smoothing_group, Arc::new(RwLock::new(ObjSmoothGroup::default())));
472						matgroup.smooth_groups.get_mut(&smoothing_group).unwrap()
473					};
474					last_smoothing_group = Some(smthgroup.clone());
475				}
476				let mut group_lock = last_smoothing_group.as_ref().unwrap().write().unwrap();
477				if line.starts_with("f ") {
478					// Process as triangle strip
479					let mut vtn_indices: Vec<ObjVTNIndex> = Vec::with_capacity(parts.len());
480					for part in parts.iter() {
481						vtn_indices.push(ObjVTNIndex::parse(line_number, part)?);
482					}
483					for i in 1..(parts.len() - 1) {
484						group_lock.triangles.push((vtn_indices[0], vtn_indices[i], vtn_indices[i + 1]));
485					}
486				} else {
487					// Process as line link
488					let mut indices: Vec<u32> = Vec::with_capacity(parts.len());
489					for part in parts.iter() {
490						match part.parse() {
491							Ok(index) => indices.push(index),
492							Err(e) => {
493								eprintln!("Parse line {line_number} error: `{line}`: {e:?}");
494								continue;
495							}
496						}
497					}
498					group_lock.lines.push(indices);
499				}
500			} else if let Some(data) = line.strip_prefix("o ") {
501				object_name = data.trim().to_string();
502				last_smoothing_group = None;
503			} else if let Some(data) = line.strip_prefix("g ") {
504				group_name = data.trim().to_string();
505				last_smoothing_group = None;
506			} else if let Some(data) = line.strip_prefix("usemtl ") {
507				material_name = data.trim().to_string();
508				last_smoothing_group = None;
509			} else if let Some(data) = line.strip_prefix("s ") {
510				smoothing_group = data.trim().parse().unwrap_or(0);
511				last_smoothing_group = None;
512			} else {
513				eprintln!("Ignoring line `{line_number}`: unknown `{line}`");
514			}
515		}
516		Ok(Self {
517			vertices,
518			normals,
519			texcoords,
520			objects,
521			materials,
522		})
523	}
524
525	/// Get the number of the mesh groups
526	pub fn get_num_groups(&self) -> usize {
527		let mut ret = 0;
528		for object in self.objects.values() {
529			for group in object.groups.values() {
530				for matgroup in group.material_groups.values() {
531					ret += matgroup.smooth_groups.len();
532				}
533			}
534		}
535		ret
536	}
537
538	/// Convert to VTN vertices and associated indices
539	pub fn convert_to_indexed_meshes<E>(&self) -> Result<ObjIndexedMeshSet<F, E>, ObjError>
540	where
541		E: ObjMeshIndexType {
542		let mut face_vertices_map: HashMap<ObjVTNIndex, E> = HashMap::new();
543		let mut line_vertices_map: HashMap<LineVert<F>, E> = HashMap::new();
544		let mut ret: ObjIndexedMeshSet<F, E> = ObjIndexedMeshSet::default();
545		for (object_name, object) in self.objects.iter() {
546			for (group_name, group) in object.groups.iter() {
547				for (material_name, matgroup) in group.material_groups.iter() {
548					for (smooth_group, smthgroup) in matgroup.smooth_groups.iter() {
549						let lock = smthgroup.read().unwrap();
550						let mut lines_vert_indices: Vec<Vec<E>> = Vec::with_capacity(lock.lines.len());
551						let mut triangle_vert_indices: Vec<(E, E, E)> = Vec::with_capacity(lock.triangles.len());
552						for line in lock.lines.iter() {
553							let mut line_vert_indices: Vec<E> = Vec::with_capacity(line.len());
554							for vert_idx in line.iter() {
555								let vert = self.vertices[*vert_idx as usize - 1];
556								line_vert_indices.push(get_line_vert_index(&mut line_vertices_map, &vert)?);
557							}
558							lines_vert_indices.push(line_vert_indices);
559						}
560						for triangle in lock.triangles.iter() {
561							let vert1 = get_face_vert_index(&mut face_vertices_map, &triangle.0)?;
562							let vert2 = get_face_vert_index(&mut face_vertices_map, &triangle.1)?;
563							let vert3 = get_face_vert_index(&mut face_vertices_map, &triangle.2)?;
564							triangle_vert_indices.push((vert1, vert2, vert3));
565						}
566						ret.meshes.push(ObjIndexedMesh {
567							object_name: object_name.clone(),
568							group_name: group_name.clone(),
569							material_name: material_name.clone(),
570							smooth_group: *smooth_group,
571							face_indices: triangle_vert_indices,
572							line_indices: lines_vert_indices,
573						});
574					}
575				}
576			}
577		}
578		ret.face_vertices.resize(face_vertices_map.len(), ObjVertices::default());
579		ret.line_vertices.resize(line_vertices_map.len(), TVec3::default());
580		for (vtn, vi) in face_vertices_map.iter() {
581			let vi: usize = (*vi).try_into().map_err(|_| ObjError::MeshIndicesOverflow)?;
582			ret.face_vertices[vi] = ObjVertices {
583				position: if vtn.v == 0 {return Err(ObjError::MeshIndicesUnderflow)} else {self.vertices[vtn.v as usize - 1]},
584				texcoord: if vtn.vt == 0 {None} else {Some(self.texcoords[vtn.vt as usize - 1])},
585				normal: if vtn.vn == 0 {None} else {Some(self.normals[vtn.vn as usize - 1])},
586				tangent: None,
587			};
588		}
589		for (lv, li) in line_vertices_map.iter() {
590			let li: usize = (*li).try_into().map_err(|_| ObjError::MeshIndicesOverflow)?;
591			ret.line_vertices[li] = TVec3::new(lv.x, lv.y, lv.z);
592		}
593		Ok(ret)
594	}
595
596	/// Convert to VTN vertices without indices
597	pub fn convert_to_unindexed_meshes(&self) -> Result<Vec<ObjUnindexedMesh<F>>, ObjError> {
598		let mut ret: Vec<ObjUnindexedMesh<F>> = Vec::with_capacity(self.get_num_groups());
599		fn get_face_vert<F>(vertices: &[TVec3<F>], texcoords: &[TVec3<F>], normals: &[TVec3<F>], vtn: &ObjVTNIndex) -> Result<ObjVertices<F>, ObjError>
600		where
601			F: ObjMeshVecCompType {
602			Ok(ObjVertices {
603				position: if vtn.v == 0 {return Err(ObjError::MeshIndicesUnderflow)} else {vertices[vtn.v as usize - 1]},
604				texcoord: if vtn.vt == 0 {None} else {Some(texcoords[vtn.vt as usize - 1])},
605				normal: if vtn.vn == 0 {None} else {Some(normals[vtn.vn as usize - 1])},
606				tangent: None,
607			})
608		}
609		for (object_name, object) in self.objects.iter() {
610			for (group_name, group) in object.groups.iter() {
611				for (material_name, matgroup) in group.material_groups.iter() {
612					for (smooth_group, smthgroup) in matgroup.smooth_groups.iter() {
613						let lock = smthgroup.read().unwrap();
614						let mut lines: Vec<Vec<TVec3<F>>> = Vec::with_capacity(lock.lines.len());
615						let mut faces: Vec<(ObjVertices<F>, ObjVertices<F>, ObjVertices<F>)> = Vec::with_capacity(lock.triangles.len());
616						for line in lock.lines.iter() {
617							let mut line_verts: Vec<TVec3<F>> = Vec::with_capacity(line.len());
618							for vert_idx in line.iter() {
619								let vert = self.vertices[*vert_idx as usize - 1];
620								line_verts.push(vert);
621							}
622							lines.push(line_verts);
623						}
624						for triangle in lock.triangles.iter() {
625							let vert1 = get_face_vert(&self.vertices, &self.texcoords, &self.normals, &triangle.0)?;
626							let vert2 = get_face_vert(&self.vertices, &self.texcoords, &self.normals, &triangle.1)?;
627							let vert3 = get_face_vert(&self.vertices, &self.texcoords, &self.normals, &triangle.2)?;
628							faces.push((vert1, vert2, vert3));
629						}
630						ret.push(ObjUnindexedMesh {
631							object_name: object_name.clone(),
632							group_name: group_name.clone(),
633							material_name: material_name.clone(),
634							smooth_group: *smooth_group,
635							faces,
636							lines,
637						});
638					}
639				}
640			}
641		}
642		Ok(ret)
643	}
644}
645
646fn float_is_zero_restrict<F>(f: F) -> bool
647where
648	F: ObjMeshVecCompType {
649	match size_of::<F>() {
650		1 => unsafe {*(&f as *const F as *const u8 ) == 0},
651		2 => unsafe {*(&f as *const F as *const u16) == 0},
652		4 => unsafe {*(&f as *const F as *const u32) == 0},
653		8 => unsafe {*(&f as *const F as *const u64) == 0},
654		o => panic!("Invalid primitive type of `<F>`, the size of this type is `{o}`"),
655	}
656}
657
658impl<F> ObjVertices<F>
659where
660	F: ObjMeshVecCompType {
661	/// Generate tangents per 3 vertices
662	pub fn generate_tangents(v1: &mut Self, v2: &mut Self, v3: &mut Self) {
663		let pos0 = v1.position;
664		let pos1 = v2.position;
665		let pos2 = v3.position;
666		let uv0 = v1.texcoord.unwrap_or_default().xy();
667		let uv1 = v2.texcoord.unwrap_or_default().xy();
668		let uv2 = v3.texcoord.unwrap_or_default().xy();
669		let normal0 = v1.normal.unwrap_or_default();
670		let normal1 = v2.normal.unwrap_or_default();
671		let normal2 = v3.normal.unwrap_or_default();
672
673		let delta_pos1 = pos1 - pos0;
674		let delta_pos2 = pos2 - pos0;
675
676		let delta_uv1 = uv1 - uv0;
677		let delta_uv2 = uv2 - uv0;
678
679		let f = F::from(1.0).unwrap() / (delta_uv1.x * delta_uv2.y - delta_uv2.x * delta_uv1.y);
680
681		let tangent = TVec3::new(
682			f * (delta_uv2.y * delta_pos1.x - delta_uv1.y * delta_pos2.x),
683			f * (delta_uv2.y * delta_pos1.y - delta_uv1.y * delta_pos2.y),
684			f * (delta_uv2.y * delta_pos1.z - delta_uv1.y * delta_pos2.z),
685		);
686
687		let bitangent = TVec3::new(
688			f * (-delta_uv2.x * delta_pos1.x + delta_uv1.x * delta_pos2.x),
689			f * (-delta_uv2.x * delta_pos1.y + delta_uv1.x * delta_pos2.y),
690			f * (-delta_uv2.x * delta_pos1.z + delta_uv1.x * delta_pos2.z),
691		);
692
693		let tangent0 = Self::orthogonalize_tangent(tangent, normal0);
694		let tangent1 = Self::orthogonalize_tangent(tangent, normal1);
695		let tangent2 = Self::orthogonalize_tangent(tangent, normal2);
696
697		let tangent0 = Self::ensure_right_handed(tangent0, normal0, bitangent);
698		let tangent1 = Self::ensure_right_handed(tangent1, normal1, bitangent);
699		let tangent2 = Self::ensure_right_handed(tangent2, normal2, bitangent);
700
701		v1.tangent = Some(tangent0);
702		v2.tangent = Some(tangent1);
703		v3.tangent = Some(tangent2);
704	}
705
706	/// Orthogonalize tangents using the Gram-Schmidt procedure
707	fn orthogonalize_tangent(tangent: TVec3<F>, normal: TVec3<F>) -> TVec3<F> {
708		let n_dot_t = normal.dot(&tangent);
709		let projected = tangent - normal * n_dot_t;
710		projected.normalize()
711	}
712
713	/// Make sure the tangent space is right-handed
714	fn ensure_right_handed(tangent: TVec3<F>, normal: TVec3<F>, bitangent: TVec3<F>) -> TVec3<F> {
715		let calculated_bitangent = normal.cross(&tangent);
716		let dot_product = calculated_bitangent.dot(&bitangent);
717
718		// If the dot product is negative, it means it is a left-handed system and the tangent needs to be flipped
719		if dot_product < F::from(0.0).unwrap() {
720			-tangent
721		} else {
722			tangent
723		}
724	}
725}
726
727impl<F> ObjUnindexedMesh<F>
728where
729	F: ObjMeshVecCompType {
730	/// Get the dimension data of vertex position, texcoord, normal
731	pub fn get_vert_dims(&self) -> (u32, u32, u32) {
732		let mut max_position = 0;
733		let mut max_texcoord = 0;
734		let mut max_normal = 0;
735		for vert in self.faces.iter().flat_map(|(a, b, c)| [a, b, c]) {
736			match max_position {
737				0 => {
738					if !float_is_zero_restrict(vert.position.z) {max_position = max(max_position, 3)}
739					else if !float_is_zero_restrict(vert.position.y) {max_position = max(max_position, 2)}
740					else if !float_is_zero_restrict(vert.position.x) {max_position = max(max_position, 1)}
741				}
742				1 => {
743					if !float_is_zero_restrict(vert.position.z) {max_position = max(max_position, 3)}
744					else if !float_is_zero_restrict(vert.position.y) {max_position = max(max_position, 2)}
745				}
746				2 => {
747					if !float_is_zero_restrict(vert.position.z) {max_position = max(max_position, 3)}
748				}
749				_ => break,
750			}
751		}
752		for vert in self.faces.iter().flat_map(|(a, b, c)| [a, b, c]) {
753			if let Some(texcoord) = vert.texcoord {
754				match max_texcoord {
755					0 => {
756						if !float_is_zero_restrict(texcoord.z) {max_texcoord = max(max_texcoord, 3)}
757						else if !float_is_zero_restrict(texcoord.y) {max_texcoord = max(max_texcoord, 2)}
758						else if !float_is_zero_restrict(texcoord.x) {max_texcoord = max(max_texcoord, 1)}
759					}
760					1 => {
761						if !float_is_zero_restrict(texcoord.z) {max_texcoord = max(max_texcoord, 3)}
762						else if !float_is_zero_restrict(texcoord.y) {max_texcoord = max(max_texcoord, 2)}
763					}
764					2 => {
765						if !float_is_zero_restrict(texcoord.z) {max_texcoord = max(max_texcoord, 3)}
766					}
767					_ => break,
768				}
769			}
770		}
771		for vert in self.faces.iter().flat_map(|(a, b, c)| [a, b, c]) {
772			if let Some(normal) = vert.normal {
773				match max_normal {
774					0 => {
775						if !float_is_zero_restrict(normal.z) {max_normal = max(max_normal, 3)}
776						else if !float_is_zero_restrict(normal.y) {max_normal = max(max_normal, 2)}
777						else if !float_is_zero_restrict(normal.x) {max_normal = max(max_normal, 1)}
778					}
779					1 => {
780						if !float_is_zero_restrict(normal.z) {max_normal = max(max_normal, 3)}
781						else if !float_is_zero_restrict(normal.y) {max_normal = max(max_normal, 2)}
782					}
783					2 => {
784						if !float_is_zero_restrict(normal.z) {max_normal = max(max_normal, 3)}
785					}
786					_ => break,
787				}
788			}
789		}
790		(max_position, max_texcoord, max_normal)
791	}
792
793	/// Only the unindexed mesh could be able to generate tangent
794	pub fn generate_tangents(&mut self) -> Result<(), ObjError> {
795		let (_, tdim, ndim) = self.get_vert_dims();
796		if tdim == 0 || ndim == 0 {
797			Err(ObjError::NeedTexCoordAndNormal)
798		} else {
799			for (v1, v2, v3) in self.faces.iter_mut() {
800				ObjVertices::generate_tangents(v1, v2, v3);
801			}
802			Ok(())
803		}
804	}
805
806	/// Convert to the indexed mesh
807	pub fn convert_to_indexed_meshes<E>(unindexed_meshes: &[Self]) -> Result<ObjIndexedMeshSet<F, E>, ObjError>
808	where
809		E: ObjMeshIndexType {
810		let mut face_vertices_map: HashMap<ObjVertices<F>, E> = HashMap::new();
811		let mut line_vertices_map: HashMap<LineVert<F>, E> = HashMap::new();
812		let mut ret: ObjIndexedMeshSet<F, E> = ObjIndexedMeshSet::default();
813		for uimesh in unindexed_meshes.iter() {
814			let mut lines_vert_indices: Vec<Vec<E>> = Vec::with_capacity(uimesh.lines.len());
815			let mut triangle_vert_indices: Vec<(E, E, E)> = Vec::with_capacity(uimesh.faces.len());
816			for line in uimesh.lines.iter() {
817				let mut line_vert_indices: Vec<E> = Vec::with_capacity(line.len());
818				for vert in line.iter() {
819					line_vert_indices.push(get_line_vert_index(&mut line_vertices_map, vert)?);
820				}
821				lines_vert_indices.push(line_vert_indices);
822			}
823			for triangle in uimesh.faces.iter() {
824				let vert1 = get_face_vert_index(&mut face_vertices_map, &triangle.0)?;
825				let vert2 = get_face_vert_index(&mut face_vertices_map, &triangle.1)?;
826				let vert3 = get_face_vert_index(&mut face_vertices_map, &triangle.2)?;
827				triangle_vert_indices.push((vert1, vert2, vert3));
828			}
829			ret.meshes.push(ObjIndexedMesh {
830				object_name: uimesh.object_name.clone(),
831				group_name: uimesh.group_name.clone(),
832				material_name: uimesh.material_name.clone(),
833				smooth_group: uimesh.smooth_group,
834				face_indices: triangle_vert_indices,
835				line_indices: lines_vert_indices,
836			});
837		}
838		ret.face_vertices.resize(face_vertices_map.len(), ObjVertices::default());
839		ret.line_vertices.resize(line_vertices_map.len(), TVec3::default());
840		for (fv, vi) in face_vertices_map.iter() {
841			let vi: usize = (*vi).try_into().map_err(|_| ObjError::MeshIndicesOverflow)?;
842			ret.face_vertices[vi] = *fv;
843		}
844		for (lv, li) in line_vertices_map.iter() {
845			let li: usize = (*li).try_into().map_err(|_| ObjError::MeshIndicesOverflow)?;
846			ret.line_vertices[li] = TVec3::new(lv.x, lv.y, lv.z);
847		}
848		Ok(ret)
849	}
850}
851
852impl<F, E> ObjIndexedMeshSet<F, E>
853where
854	F: ObjMeshVecCompType,
855	E: ObjMeshIndexType {
856	/// Get the dimension data of vertex position, texcoord, normal
857	pub fn get_vert_dims(&self) -> (u32, u32, u32) {
858		let mut max_position = 0;
859		let mut max_texcoord = 0;
860		let mut max_normal = 0;
861		for vert in self.face_vertices.iter() {
862			match max_position {
863				0 => {
864					if !float_is_zero_restrict(vert.position.z) {max_position = max(max_position, 3)}
865					else if !float_is_zero_restrict(vert.position.y) {max_position = max(max_position, 2)}
866					else if !float_is_zero_restrict(vert.position.x) {max_position = max(max_position, 1)}
867				}
868				1 => {
869					if !float_is_zero_restrict(vert.position.z) {max_position = max(max_position, 3)}
870					else if !float_is_zero_restrict(vert.position.y) {max_position = max(max_position, 2)}
871				}
872				2 => {
873					if !float_is_zero_restrict(vert.position.z) {max_position = max(max_position, 3)}
874				}
875				_ => break,
876			}
877		}
878		for vert in self.face_vertices.iter() {
879			if let Some(texcoord) = vert.texcoord {
880				match max_texcoord {
881					0 => {
882						if !float_is_zero_restrict(texcoord.z) {max_texcoord = max(max_texcoord, 3)}
883						else if !float_is_zero_restrict(texcoord.y) {max_texcoord = max(max_texcoord, 2)}
884						else if !float_is_zero_restrict(texcoord.x) {max_texcoord = max(max_texcoord, 1)}
885					}
886					1 => {
887						if !float_is_zero_restrict(texcoord.z) {max_texcoord = max(max_texcoord, 3)}
888						else if !float_is_zero_restrict(texcoord.y) {max_texcoord = max(max_texcoord, 2)}
889					}
890					2 => {
891						if !float_is_zero_restrict(texcoord.z) {max_texcoord = max(max_texcoord, 3)}
892					}
893					_ => break,
894				}
895			}
896		}
897		for vert in self.face_vertices.iter() {
898			if let Some(normal) = vert.normal {
899				match max_normal {
900					0 => {
901						if !float_is_zero_restrict(normal.z) {max_normal = max(max_normal, 3)}
902						else if !float_is_zero_restrict(normal.y) {max_normal = max(max_normal, 2)}
903						else if !float_is_zero_restrict(normal.x) {max_normal = max(max_normal, 1)}
904					}
905					1 => {
906						if !float_is_zero_restrict(normal.z) {max_normal = max(max_normal, 3)}
907						else if !float_is_zero_restrict(normal.y) {max_normal = max(max_normal, 2)}
908					}
909					2 => {
910						if !float_is_zero_restrict(normal.z) {max_normal = max(max_normal, 3)}
911					}
912					_ => break,
913				}
914			}
915		}
916		(max_position, max_texcoord, max_normal)
917	}
918
919	/// Convert to the unindexed mesh
920	pub fn convert_to_unindexed_meshes(&self) -> Result<Vec<ObjUnindexedMesh<F>>, ObjError> {
921		let mut ret = Vec::new();
922		for mesh in self.meshes.iter() {
923			let mut faces = Vec::with_capacity(self.face_vertices.len());
924			let mut lines = Vec::with_capacity(self.line_vertices.len());
925			for (i1, i2, i3) in mesh.face_indices.iter() {
926				let v1 = self.face_vertices[TryInto::<usize>::try_into(*i1).map_err(|_| ObjError::MeshIndicesOverflow)?];
927				let v2 = self.face_vertices[TryInto::<usize>::try_into(*i2).map_err(|_| ObjError::MeshIndicesOverflow)?];
928				let v3 = self.face_vertices[TryInto::<usize>::try_into(*i3).map_err(|_| ObjError::MeshIndicesOverflow)?];
929				faces.push((v1, v2, v3));
930			}
931			for line in mesh.line_indices.iter() {
932				let mut verts = Vec::with_capacity(line.len());
933				for i in line.iter() {
934					verts.push(self.line_vertices[TryInto::<usize>::try_into(*i).map_err(|_| ObjError::MeshIndicesOverflow)?]);
935				}
936				lines.push(verts);
937			}
938			ret.push(ObjUnindexedMesh {
939				object_name: mesh.object_name.clone(),
940				group_name: mesh.group_name.clone(),
941				material_name: mesh.material_name.clone(),
942				smooth_group: mesh.smooth_group,
943				faces,
944				lines,
945			});
946		}
947		Ok(ret)
948	}
949}
950
951/// The material component
952#[derive(Clone)]
953pub enum ObjMaterialComponent {
954	Texture(PathBuf),
955	Color(Vec4),
956	Luminance(f32),
957}
958
959impl Debug for ObjMaterialComponent {
960	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
961		match self {
962			Self::Texture(filename) => write!(f, "Texture(\"{}\")", filename.display()),
963			Self::Color(c) => write!(f, "Color({}, {}, {}, {})", c.x, c.y, c.z, c.w),
964			Self::Luminance(lum) => write!(f, "Luminance({lum})"),
965		}
966	}
967}
968
969/// The legacy illumination model material
970#[derive(Debug, Clone)]
971pub struct ObjMaterialLegacy {
972	/// Base brightness
973	pub ambient: ObjMaterialComponent,
974
975	/// Base color
976	pub diffuse: ObjMaterialComponent,
977
978	/// Specular color
979	pub specular: ObjMaterialComponent,
980
981	/// Specular power
982	pub specular_power: ObjMaterialComponent,
983
984	/// Normal map
985	pub normal: ObjMaterialComponent,
986
987	/// Emissive, self-lighting
988	pub emissive: ObjMaterialComponent,
989
990	/// The other type of components
991	pub others: HashMap<String, ObjMaterialComponent>,
992}
993
994impl Default for ObjMaterialLegacy {
995	fn default() -> Self {
996		Self {
997			ambient: ObjMaterialComponent::default(),
998			diffuse: ObjMaterialComponent::default(),
999			specular: ObjMaterialComponent::default(),
1000			specular_power: ObjMaterialComponent::Luminance(1.0),
1001			normal: ObjMaterialComponent::default(),
1002			emissive: ObjMaterialComponent::default(),
1003			others: HashMap::new(),
1004		}
1005	}
1006}
1007
1008/// The physically based rendering illumination model material
1009#[derive(Default, Debug, Clone)]
1010pub struct ObjMaterialPbr {
1011	/// Base color
1012	pub albedo: ObjMaterialComponent,
1013
1014	/// Normal map
1015	pub normal: ObjMaterialComponent,
1016
1017	/// Ambient occlusion
1018	pub ao: ObjMaterialComponent,
1019
1020	/// A.k.a. Height map. The renderer must render this map by extruding the mesh, or use ray-marching to cast the protrusions of the map
1021	pub displacement: ObjMaterialComponent,
1022
1023	/// Roughness, something sort of the legacy specular-key map
1024	pub roughness: ObjMaterialComponent,
1025
1026	/// Metalness, something sort of the legacy specular map
1027	pub metalness: ObjMaterialComponent,
1028
1029	/// Emissive, self-lighting
1030	pub emissive: ObjMaterialComponent,
1031
1032	/// The other type of components
1033	pub others: HashMap<String, ObjMaterialComponent>,
1034}
1035
1036impl Default for ObjMaterialComponent {
1037	fn default() -> Self {
1038		Self::Color(Vec4::new(0.5, 0.5, 0.5, 1.0))
1039	}
1040}
1041
1042/// The `Material` trait helps the `MaterialLegacy` struct or the `MaterialPbr` struct to be able to turn into an object
1043pub trait ObjMaterial: Debug + Any {
1044	/// Get the ambient color
1045	fn get_ambient(&self) -> Option<&ObjMaterialComponent>;
1046
1047	/// Get the diffuse color
1048	fn get_diffuse(&self) -> Option<&ObjMaterialComponent>;
1049
1050	/// Get the specular color
1051	fn get_specular(&self) -> Option<&ObjMaterialComponent>;
1052
1053	/// Get the specular power
1054	fn get_specular_power(&self) -> Option<&ObjMaterialComponent>;
1055
1056	/// Get the base color (PBR)
1057	fn get_albedo(&self) -> Option<&ObjMaterialComponent>;
1058
1059	/// Get the ambient occlusion (PBR)
1060	fn get_ao(&self) -> Option<&ObjMaterialComponent>;
1061
1062	/// Get the displacement map (A.k.a. height map) (PBR)
1063	fn get_displacement(&self) -> Option<&ObjMaterialComponent>;
1064
1065	/// Get the roughness map (PBR)
1066	fn get_roughness(&self) -> Option<&ObjMaterialComponent>;
1067
1068	/// Get the metalness map (PBR)
1069	fn get_metalness(&self) -> Option<&ObjMaterialComponent>;
1070
1071	/// Get the normal map
1072	fn get_normal(&self) -> Option<&ObjMaterialComponent>;
1073
1074	/// Get the emissive color
1075	fn get_emissive(&self) -> Option<&ObjMaterialComponent>;
1076
1077	/// Get all of the component names exists in this material
1078	fn get_names(&self) -> BTreeSet<String>;
1079
1080	/// Get a component by the name of the component
1081	fn get_by_name(&self, name: &str) -> Option<&ObjMaterialComponent>;
1082
1083	/// Set a componnet by the name of the component
1084	fn set_by_name(&mut self, name: &str, texture: ObjMaterialComponent);
1085}
1086
1087impl ObjMaterial for ObjMaterialLegacy {
1088	fn get_ambient(&self) ->		Option<&ObjMaterialComponent> {Some(&self.ambient)}
1089	fn get_diffuse(&self) ->		Option<&ObjMaterialComponent> {Some(&self.diffuse)}
1090	fn get_specular(&self) ->		Option<&ObjMaterialComponent> {Some(&self.specular)}
1091	fn get_specular_power(&self) ->	Option<&ObjMaterialComponent> {Some(&self.specular_power)}
1092	fn get_normal(&self) ->			Option<&ObjMaterialComponent> {Some(&self.normal)}
1093	fn get_emissive(&self) ->		Option<&ObjMaterialComponent> {Some(&self.emissive)}
1094
1095	fn get_albedo(&self) ->			Option<&ObjMaterialComponent> {Some(&self.diffuse)}
1096	fn get_ao(&self) ->				Option<&ObjMaterialComponent> {Some(&self.ambient)}
1097	fn get_displacement(&self) ->	Option<&ObjMaterialComponent> {None}
1098	fn get_roughness(&self) ->		Option<&ObjMaterialComponent> {None}
1099	fn get_metalness(&self) ->		Option<&ObjMaterialComponent> {None}
1100
1101	fn get_names(&self) -> BTreeSet<String> {
1102		let mut ret = BTreeSet::new();
1103		ret.insert("ambient".to_owned());
1104		ret.insert("diffuse".to_owned());
1105		ret.insert("specular".to_owned());
1106		ret.insert("specular_power".to_owned());
1107		ret.insert("normal".to_owned());
1108		ret.insert("emissive".to_owned());
1109		for (name, _) in self.others.iter() {
1110			ret.insert(name.clone());
1111		}
1112		ret
1113	}
1114
1115	fn get_by_name(&self, name: &str) -> Option<&ObjMaterialComponent> {
1116		match self.others.get(name) {
1117			Some(data) => Some(data),
1118			None => {
1119				match name {
1120					"ambient" =>		self.get_ambient(),
1121					"diffuse" =>		self.get_diffuse(),
1122					"specular" =>		self.get_specular(),
1123					"specular_power" =>	self.get_specular_power(),
1124					"normal" =>			self.get_normal(),
1125					"emissive" =>		self.get_emissive(),
1126					_ => None,
1127				}
1128			}
1129		}
1130	}
1131
1132	fn set_by_name(&mut self, name: &str, texture: ObjMaterialComponent) {
1133		match name {
1134			"ambient" =>		self.ambient = texture,
1135			"diffuse" =>		self.diffuse = texture,
1136			"specular" =>		self.specular = texture,
1137			"specular_power" =>	self.specular_power = texture,
1138			"normal" =>			self.normal = texture,
1139			"emissive" =>		self.emissive = texture,
1140			others =>{
1141				self.others.insert(others.to_owned(), texture);
1142			}
1143		}
1144	}
1145}
1146
1147impl ObjMaterial for ObjMaterialPbr {
1148	fn get_albedo(&self) ->			Option<&ObjMaterialComponent> {Some(&self.albedo)}
1149	fn get_ao(&self) ->				Option<&ObjMaterialComponent> {Some(&self.ao)}
1150	fn get_displacement(&self) ->	Option<&ObjMaterialComponent> {Some(&self.displacement)}
1151	fn get_roughness(&self) ->		Option<&ObjMaterialComponent> {Some(&self.roughness)}
1152	fn get_metalness(&self) ->		Option<&ObjMaterialComponent> {Some(&self.metalness)}
1153	fn get_normal(&self) ->			Option<&ObjMaterialComponent> {Some(&self.normal)}
1154	fn get_emissive(&self) ->		Option<&ObjMaterialComponent> {Some(&self.emissive)}
1155
1156	fn get_ambient(&self) ->		Option<&ObjMaterialComponent> {Some(&self.ao)}
1157	fn get_diffuse(&self) ->		Option<&ObjMaterialComponent> {Some(&self.albedo)}
1158	fn get_specular(&self) ->		Option<&ObjMaterialComponent> {None}
1159	fn get_specular_power(&self) ->	Option<&ObjMaterialComponent> {None}
1160
1161	fn get_names(&self) -> BTreeSet<String> {
1162		let mut ret = BTreeSet::new();
1163		ret.insert("albedo".to_owned());
1164		ret.insert("ao".to_owned());
1165		ret.insert("displacement".to_owned());
1166		ret.insert("roughness".to_owned());
1167		ret.insert("metalness".to_owned());
1168		ret.insert("normal".to_owned());
1169		ret.insert("emissive".to_owned());
1170		for (name, _) in self.others.iter() {
1171			ret.insert(name.clone());
1172		}
1173		ret
1174	}
1175
1176	fn get_by_name(&self, name: &str) -> Option<&ObjMaterialComponent> {
1177		match self.others.get(name) {
1178			Some(data) => Some(data),
1179			None => {
1180				match name {
1181					"albedo" =>			self.get_albedo(),
1182					"ao" =>				self.get_ao(),
1183					"displacement" =>	self.get_displacement(),
1184					"roughness" =>		self.get_roughness(),
1185					"metalness" =>		self.get_metalness(),
1186					"normal" =>			self.get_normal(),
1187					"emissive" =>		self.get_emissive(),
1188					_ => None,
1189				}
1190			}
1191		}
1192	}
1193
1194	fn set_by_name(&mut self, name: &str, texture: ObjMaterialComponent) {
1195		match name {
1196			"albedo" =>			self.albedo = texture,
1197			"ao" =>				self.ao = texture,
1198			"displacement" =>	self.displacement = texture,
1199			"roughness" =>		self.roughness = texture,
1200			"metalness" =>		self.metalness = texture,
1201			"normal" =>			self.normal = texture,
1202			"emissive" =>		self.emissive = texture,
1203			others =>{
1204				self.others.insert(others.to_owned(), texture);
1205			}
1206		}
1207	}
1208}
1209
1210/// The material loader for the OBJ mesh
1211#[derive(Debug, Clone)]
1212pub struct ObjMaterialLoader {
1213	/// The path of the MTL file
1214	pub path: PathBuf,
1215
1216	/// The materials of the OBJ file
1217	pub materials: BTreeMap<String, Arc<RwLock<dyn ObjMaterial>>>,
1218
1219	/// The current loading material name
1220	pub cur_material_name: String,
1221
1222	/// The current material fields
1223	pub cur_material_fields: BTreeMap<String, (usize, String)>,
1224}
1225
1226impl ObjMaterialLoader {
1227	/// Parse a MTL file
1228	pub fn from_file<P: AsRef<Path>>(path: P) -> Result<BTreeMap<String, Arc<RwLock<dyn ObjMaterial>>>, ObjError> {
1229		let reader = BufReader::new(File::open(&path)?);
1230		let mut ret = Self {
1231			path: PathBuf::from(path.as_ref()),
1232			materials: BTreeMap::new(),
1233			cur_material_name: String::default(),
1234			cur_material_fields: BTreeMap::new(),
1235		};
1236		for (line_number, line) in reader.lines().enumerate() {
1237			let line = line?;
1238			let line = concentrate_line(&line);
1239			if line.is_empty() {
1240				continue;
1241			}
1242			ret.process_line(line_number, line)?;
1243		}
1244		ret.finish_material();
1245		Ok(ret.materials)
1246	}
1247
1248	/// Process a line of the material
1249	pub fn process_line(&mut self, line_number: usize, line: &str) -> Result<(), ObjError> {
1250		if let Some(material_name) = line.strip_prefix("newmtl ") {
1251			self.finish_material();
1252			self.cur_material_name = material_name.trim().to_string();
1253			Ok(())
1254		} else if let Some((key, value)) = line.split_once(' ') {
1255			self.cur_material_fields.insert(key.to_string(), (line_number, value.to_string()));
1256			Ok(())
1257		} else {
1258			Err(ObjError::ParseError {
1259				line: line_number,
1260				what: format!("Unknown line: `{line}`"),
1261			})
1262		}
1263	}
1264
1265	/// Check if the current material is a PBR material
1266	fn cur_is_pbr(&self) -> bool {
1267		let pbr_slots = [
1268			"Pr",
1269			"Pm",
1270			"Ps",
1271			"aniso",
1272			"disp",
1273		];
1274		for slot in pbr_slots {
1275			let pure_color = slot;
1276			let mapped_color = format!("map_{slot}");
1277			if self.cur_material_fields.contains_key(pure_color) {
1278				return true;
1279			}
1280			if self.cur_material_fields.contains_key(&mapped_color) {
1281				return true;
1282			}
1283		}
1284		false
1285	}
1286
1287	/// Finish the current material
1288	pub fn finish_material(&mut self) {
1289		if self.cur_material_name.is_empty() || self.cur_material_fields.is_empty() {
1290			return;
1291		}
1292		let new_mat: Arc<RwLock<dyn ObjMaterial>> = if self.cur_is_pbr() {
1293			Arc::new(RwLock::new(ObjMaterialPbr::default()))
1294		} else {
1295			Arc::new(RwLock::new(ObjMaterialLegacy::default()))
1296		};
1297		static LEGACY_SLOT_MAP: OnceLock<HashMap<&'static str, &'static str>> = OnceLock::new();
1298		static PBR_SLOT_MAP: OnceLock<HashMap<&'static str, &'static str>> = OnceLock::new();
1299		let legacy_slot_map = LEGACY_SLOT_MAP.get_or_init(|| {
1300			[
1301				("Ka", "ambient"),
1302				("Kd", "diffuse"),
1303				("Ks", "specular"),
1304				("Ns", "specular_power"),
1305				("norm", "normal"),
1306				("Ke", "emissive"),
1307			].into_iter().collect()
1308		});
1309		let pbr_slot_map = PBR_SLOT_MAP.get_or_init(|| {
1310			let mut ret = legacy_slot_map.clone();
1311			ret.insert("Kd", "albedo");
1312			ret.insert("Pr", "roughness");
1313			ret.insert("Pm", "metalness");
1314			ret.insert("Ps", "sheen");
1315			ret.insert("aniso", "anisotropy");
1316			ret.insert("disp", "displacement");
1317			ret
1318		});
1319		let slot_map = if self.cur_is_pbr() {
1320			&pbr_slot_map
1321		} else {
1322			&legacy_slot_map
1323		};
1324		let mut mat_lock = new_mat.write().unwrap();
1325		for (key, value) in self.cur_material_fields.iter() {
1326			let (line_number, value) = value;
1327			let mut is_map = false;
1328			let slot_name = if let Some(suffix) = key.strip_prefix("map_") {
1329				is_map = true;
1330				suffix.to_string()
1331			} else {
1332				key.to_string()
1333			};
1334			if slot_name == "norm" || slot_name == "disp" {
1335				is_map = true;
1336			}
1337			if is_map {
1338				let slot_name: &str = &slot_name;
1339				let slot_name_mapped = slot_map.get(&slot_name).unwrap_or(&slot_name).to_string();
1340				let mut texture_file_path = self.path.clone();
1341				texture_file_path.set_file_name(value);
1342				mat_lock.set_by_name(&slot_name_mapped, ObjMaterialComponent::Texture(texture_file_path));
1343			} else {
1344				let slot_name: &str = &slot_name;
1345				let slot_name_mapped = slot_map.get(&slot_name).unwrap_or(&slot_name).to_string();
1346				let parts: Vec<&str> = value.split_whitespace().collect();
1347				if parts.len() == 3 {
1348					let r = if let Ok(number) = parts[0].parse::<f32>() {number} else {eprintln!("Ignored material line in {line_number}: {key} {value}"); continue;};
1349					let g = if let Ok(number) = parts[1].parse::<f32>() {number} else {eprintln!("Ignored material line in {line_number}: {key} {value}"); continue;};
1350					let b = if let Ok(number) = parts[2].parse::<f32>() {number} else {eprintln!("Ignored material line in {line_number}: {key} {value}"); continue;};
1351					mat_lock.set_by_name(&slot_name_mapped, ObjMaterialComponent::Color(Vec4::new(r, g, b, 1.0)));
1352				} else if let Ok(number) = value.parse::<f32>() {
1353					mat_lock.set_by_name(&slot_name_mapped, ObjMaterialComponent::Luminance(number));
1354				} else {
1355					eprintln!("Ignored material line in {line_number}: {key} {value}");
1356				}
1357			}
1358		}
1359		drop(mat_lock);
1360		self.materials.insert(self.cur_material_name.clone(), new_mat);
1361		self.cur_material_fields = BTreeMap::new();
1362	}
1363}