1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::io::*;
use std::collections::HashMap;
use std::path::Path;
use crate::{CPUMesh, CPUMaterial};
pub struct Obj {
}
impl Obj {
pub fn parse<P: AsRef<Path>>(loaded: &Loaded, path: P) -> Result<(Vec<CPUMesh>, Vec<CPUMaterial>), Error> {
let obj_bytes = Loader::get(loaded, path.as_ref()).unwrap();
let obj = wavefront_obj::obj::parse(String::from_utf8(obj_bytes.to_owned()).unwrap())?;
let p = path.as_ref().parent().unwrap();
let mut cpu_materials = Vec::new();
if let Some(material_library) = obj.material_library {
let bytes = Loader::get(loaded, p.join(material_library).to_str().unwrap()).unwrap().to_owned();
let materials = wavefront_obj::mtl::parse(String::from_utf8(bytes).unwrap()).unwrap().materials;
for material in materials {
let color = if material.color_diffuse.r != material.color_diffuse.g || material.color_diffuse.g != material.color_diffuse.b { material.color_diffuse }
else if material.color_specular.r != material.color_specular.g || material.color_specular.g != material.color_specular.b { material.color_specular }
else if material.color_ambient.r != material.color_ambient.g || material.color_ambient.g != material.color_ambient.b { material.color_ambient }
else {material.color_diffuse};
let diffuse_intensity = (material.color_diffuse.r as f32).max(material.color_diffuse.g as f32).max(material.color_diffuse.b as f32);
let specular_intensity = (material.color_specular.r as f32).max(material.color_specular.g as f32).max(material.color_specular.b as f32);
cpu_materials.push(CPUMaterial {
name: material.name,
color: Some((color.r as f32, color.g as f32, color.b as f32, material.alpha as f32)),
diffuse_intensity: Some(diffuse_intensity),
specular_intensity: Some(specular_intensity),
specular_power: Some(material.specular_coefficient as f32),
texture_image: if let Some(path) = material.uv_map.as_ref().map(|texture_name| p.join(texture_name).to_str().unwrap().to_owned())
{
Some(Loader::get_image(loaded, &path)?)
} else {None}
});
}
}
let mut cpu_meshes = Vec::new();
for object in obj.objects.iter() {
for mesh in object.geometry.iter() {
let mut positions = Vec::new();
let mut normals = Vec::new();
let mut uvs = Vec::new();
let mut indices = Vec::new();
let mut map: HashMap<usize, usize> = HashMap::new();
let mut process = |i: wavefront_obj::obj::VTNIndex| {
let mut index = map.get(&i.0).map(|v| *v);
let uvw = i.1.map(|tex_index| object.tex_vertices[tex_index]);
let normal = i.2.map(|normal_index| object.normals[normal_index]);
if let Some(ind) = index {
if let Some(tex) = uvw {
if ((uvs[ind*2] - tex.u as f32) as f32).abs() > std::f32::EPSILON ||
((uvs[ind*2+1] - tex.v as f32) as f32).abs() > std::f32::EPSILON {
index = None;
}
}
if let Some(n) = normal {
if ((normals[ind*3] - n.x as f32) as f32).abs() > std::f32::EPSILON ||
((normals[ind*3+1] - n.y as f32) as f32).abs() > std::f32::EPSILON ||
((normals[ind*3+2] - n.z as f32) as f32).abs() > std::f32::EPSILON {
index = None;
}
}
}
if index.is_none() {
index = Some(positions.len() / 3);
map.insert(i.0, index.unwrap());
let position = object.vertices[i.0];
positions.push(position.x as f32);
positions.push(position.y as f32);
positions.push(position.z as f32);
if let Some(tex) = uvw {
uvs.push(tex.u as f32);
uvs.push(tex.v as f32);
}
if let Some(n) = normal {
normals.push(n.x as f32);
normals.push(n.y as f32);
normals.push(n.z as f32);
}
}
indices.push(index.unwrap() as u32);
};
for shape in mesh.shapes.iter() {
match shape.primitive {
wavefront_obj::obj::Primitive::Triangle(i0, i1, i2) => {
process(i0);
process(i1);
process(i2);
},
_ => {}
}
}
cpu_meshes.push(CPUMesh {
name: object.name.to_string(),
material_name: mesh.material_name.clone(),
positions,
indices: Some(indices),
normals: Some(normals),
uvs: Some(uvs)
});
}
}
Ok((cpu_meshes, cpu_materials))
}
}