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#[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#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct ObjVTNIndex {
43 pub v: u32,
45
46 pub vt: u32,
48
49 pub vn: u32,
51}
52
53impl ObjVTNIndex {
54 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#[derive(Default, Debug, Clone)]
96pub struct ObjSmoothGroup {
97 pub lines: Vec<Vec<u32>>,
99
100 pub triangles: Vec<(ObjVTNIndex, ObjVTNIndex, ObjVTNIndex)>,
102}
103
104#[derive(Default, Debug, Clone)]
106pub struct ObjMaterialGroup {
107 pub smooth_groups: BTreeMap<i32, Arc<RwLock<ObjSmoothGroup>>>,
109}
110
111#[derive(Default, Debug, Clone)]
113pub struct ObjGroups {
114 pub material_groups: BTreeMap<String, ObjMaterialGroup>,
116}
117
118#[derive(Default, Debug, Clone)]
120pub struct ObjObjects {
121 pub groups: BTreeMap<String, ObjGroups>,
123}
124
125pub 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
131pub 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
135pub 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 pub position: TVec3<F>,
145
146 pub texcoord: Option<TVec3<F>>,
148
149 pub normal: Option<TVec3<F>>,
151
152 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 pub object_name: String,
209
210 pub group_name: String,
212
213 pub material_name: String,
215
216 pub smooth_group: i32,
218
219 pub face_indices: Vec<(E, E, E)>,
221
222 pub line_indices: Vec<Vec<E>>,
224}
225
226#[derive(Default, Debug, Clone)]
227pub struct ObjUnindexedMesh<F>
228where
229 F: ObjMeshVecCompType {
230 pub object_name: String,
232
233 pub group_name: String,
235
236 pub material_name: String,
238
239 pub smooth_group: i32,
241
242 pub faces: Vec<(ObjVertices<F>, ObjVertices<F>, ObjVertices<F>)>,
244
245 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 pub face_vertices: Vec<ObjVertices<F>>,
256
257 pub line_vertices: Vec<TVec3<F>>,
259
260 pub meshes: Vec<ObjIndexedMesh<E>>,
262}
263
264#[derive(Default, Debug, Clone)]
266pub struct ObjMesh<F>
267where
268 F: ObjMeshVecCompType {
269 pub vertices: Vec<TVec3<F>>,
271
272 pub normals: Vec<TVec3<F>>,
274
275 pub texcoords: Vec<TVec3<F>>,
277
278 pub objects: BTreeMap<String, ObjObjects>,
280
281 pub materials: BTreeMap<String, Arc<RwLock<dyn ObjMaterial>>>,
283}
284
285fn 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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#[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#[derive(Debug, Clone)]
971pub struct ObjMaterialLegacy {
972 pub ambient: ObjMaterialComponent,
974
975 pub diffuse: ObjMaterialComponent,
977
978 pub specular: ObjMaterialComponent,
980
981 pub specular_power: ObjMaterialComponent,
983
984 pub normal: ObjMaterialComponent,
986
987 pub emissive: ObjMaterialComponent,
989
990 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#[derive(Default, Debug, Clone)]
1010pub struct ObjMaterialPbr {
1011 pub albedo: ObjMaterialComponent,
1013
1014 pub normal: ObjMaterialComponent,
1016
1017 pub ao: ObjMaterialComponent,
1019
1020 pub displacement: ObjMaterialComponent,
1022
1023 pub roughness: ObjMaterialComponent,
1025
1026 pub metalness: ObjMaterialComponent,
1028
1029 pub emissive: ObjMaterialComponent,
1031
1032 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
1042pub trait ObjMaterial: Debug + Any {
1044 fn get_ambient(&self) -> Option<&ObjMaterialComponent>;
1046
1047 fn get_diffuse(&self) -> Option<&ObjMaterialComponent>;
1049
1050 fn get_specular(&self) -> Option<&ObjMaterialComponent>;
1052
1053 fn get_specular_power(&self) -> Option<&ObjMaterialComponent>;
1055
1056 fn get_albedo(&self) -> Option<&ObjMaterialComponent>;
1058
1059 fn get_ao(&self) -> Option<&ObjMaterialComponent>;
1061
1062 fn get_displacement(&self) -> Option<&ObjMaterialComponent>;
1064
1065 fn get_roughness(&self) -> Option<&ObjMaterialComponent>;
1067
1068 fn get_metalness(&self) -> Option<&ObjMaterialComponent>;
1070
1071 fn get_normal(&self) -> Option<&ObjMaterialComponent>;
1073
1074 fn get_emissive(&self) -> Option<&ObjMaterialComponent>;
1076
1077 fn get_names(&self) -> BTreeSet<String>;
1079
1080 fn get_by_name(&self, name: &str) -> Option<&ObjMaterialComponent>;
1082
1083 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#[derive(Debug, Clone)]
1212pub struct ObjMaterialLoader {
1213 pub path: PathBuf,
1215
1216 pub materials: BTreeMap<String, Arc<RwLock<dyn ObjMaterial>>>,
1218
1219 pub cur_material_name: String,
1221
1222 pub cur_material_fields: BTreeMap<String, (usize, String)>,
1224}
1225
1226impl ObjMaterialLoader {
1227 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 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 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 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}