1use super::*;
2
3pub fn load_file(file: File, material: Material) -> Result<Mesh> {
6 let mut vertices: Vec<Point> = Vec::new();
7 let mut normals: Vec<Normal> = Vec::new();
8 let mut uvs: Vec<Vec2> = Vec::new();
9 let mut faces: Vec<Face> = Vec::new();
10
11 let reader = BufReader::new(file);
12 for line in reader.lines() {
13 let line = line?.trim().to_string();
14 if line.starts_with('#') || line.is_empty() {
15 continue;
16 }
17 let tokens: Vec<&str> = line.split_ascii_whitespace().collect();
18
19 parse_tokens(tokens, &mut vertices, &mut normals, &mut uvs, &mut faces)?;
20 }
21
22 Ok(TriangleMesh::new(vertices, faces, normals, uvs, material))
23}
24
25
26pub fn load_scene(file: File, materials: HashMap<String, MtlConfig>) -> Result<Scene> {
27 let mut scene = Scene::default();
28 let mut vertices: Vec<Point> = Vec::new();
29 let mut normals: Vec<Normal> = Vec::new();
30 let mut uvs: Vec<Vec2> = Vec::new();
31 let mut faces: Vec<Face> = Vec::new();
32 let mut meshes: Vec<(Vec<Face>, Material)> = Vec::new();
33 let mut material = Material::Blank;
34
35 let reader = BufReader::new(file);
36 for line in reader.lines() {
37 let line = line?.trim().to_string();
38 if line.starts_with('#') || line.is_empty() {
39 continue;
40 }
41 let tokens: Vec<&str> = line.split_ascii_whitespace().collect();
42
43 match tokens[0] {
44 "g" | "o" => {
45 if !faces.is_empty() {
46 meshes.push((faces, material));
47 faces = Vec::new();
48 material = Material::Blank;
49 }
50 }
51 "usemtl" => {
52 match materials.get(tokens[1]) {
53 Some(mtl_cfg) => material = mtl_cfg.build_material(),
54 None => {
55 return Err(obj_error(
56 &format!("Could not find material {}", tokens[1])
57 ));
58 }
59 }
60 }
61 _ => {
62 parse_tokens(
63 tokens,
64 &mut vertices,
65 &mut normals,
66 &mut uvs,
67 &mut faces
68 )?
69 }
70 }
71 }
72
73 meshes.push((faces, material));
74
75 let triangle_mesh = Arc::new(TriangleMesh {
76 vertices,
77 normals,
78 uvs,
79 });
80
81 for (faces, mtl) in meshes {
82 let is_light = matches!(mtl, Material::Light(_));
83 let object = Box::new(TriangleMesh::new_from_faces(
84 triangle_mesh.clone(),
85 faces,
86 mtl,
87 ));
88
89 if is_light {
90 scene.add_light(object);
91 } else {
92 scene.add(object);
93 }
94 }
95
96 Ok(scene)
97}
98
99fn parse_tokens(
100 tokens: Vec<&str>,
101 vertices: &mut Vec<Point>,
102 normals: &mut Vec<Normal>,
103 uvs: &mut Vec<Vec2>,
104 faces: &mut Vec<Face>,
105) -> Result<()> {
106 match tokens[0] {
107 "v" => {
108 let vertex = parse_vec3(&tokens)?;
109 vertices.push(vertex);
110 }
111 "vn" => {
112 let normal = parse_vec3(&tokens)?;
113 normals.push(normal);
114 }
115 "vt" => {
116 let uv = parse_vec2(&tokens)?;
117 uvs.push(uv);
118 }
119 "f" => {
120 let face = parse_face(&tokens, vertices, normals, uvs)?;
121 faces.extend(face);
122 }
123 _ => (),
124 }
125 Ok(())
126}
127
128fn parse_face(
130 tokens: &[&str],
131 vertices: &[Point],
132 normals: &[Normal],
133 uvs: &[Vec2],
134) -> Result<Vec<Face>> {
135 let mut vidxs: Vec<usize> = Vec::new();
136 let mut nidxs: Vec<usize> = Vec::new();
137 let mut tidxs: Vec<usize> = Vec::new();
138
139 for token in &tokens[1..] {
140 let arguments: Vec<&str> = token.split('/').collect();
141
142 let vidx = parse_idx(arguments[0], vertices.len())?;
143 vidxs.push(vidx);
144
145 if arguments.len() > 1 && !arguments[1].is_empty() {
146 let tidx = parse_idx(arguments[1], uvs.len())?;
147 tidxs.push(tidx);
148 }
149
150 if arguments.len() > 2 {
151 let nidx = parse_idx(arguments[2], normals.len())?;
152 nidxs.push(nidx);
153 }
154 }
155
156 let mut faces: Vec<Face> = Vec::new();
157
158 for i in 1..vidxs.len() - 1 {
159 let (a, b, c) = (0, i, i + 1);
160 let vidx = vec![vidxs[a], vidxs[b], vidxs[c]];
161
162 let nidx = if nidxs.is_empty() {
163 Vec::new()
164 } else {
165 vec![nidxs[a], nidxs[b], nidxs[c]]
166 };
167
168 let tidx = if tidxs.is_empty() {
169 Vec::new()
170 } else {
171 vec![tidxs[a], tidxs[b], tidxs[c]]
172 };
173
174 faces.push(Face::new(vidx, nidx, tidx));
175 }
176
177 Ok(faces)
178}