1use std::collections::hash_map::Entry;
4use std::collections::HashMap;
5use std::hash::Hash;
6use std::io::BufRead;
7use std::mem;
8
9use crate::error::{make_error, ObjResult};
10use crate::raw::lexer::lex;
11use crate::raw::util::parse_args;
12
13macro_rules! parse_args {
14 {
15 $first:expr, $rest:expr,
16 $($pat:pat => $type:ident::$name:ident[$exp:expr]),*,
17 ! => $error:expr
18 } => (
19 match split_vertex_group($first)[..] {
20 $($pat => $type::$name({
21 let mut points = vec![$exp];
22 for param in $rest {
23 match split_vertex_group(param)[..] {
24 $pat => points.push($exp),
25 _ => $error
26 }
27 }
28 points
29 }),)*
30 _ => $error
31 }
32 )
33}
34
35fn try_index<T>(collection: &[T], input: &str) -> ObjResult<usize> {
51 use crate::error::{LoadError, LoadErrorKind, ObjError};
52
53 let len: isize = collection.len().try_into().map_err(|_| {
54 ObjError::Load(LoadError::new_internal(
55 LoadErrorKind::IndexOutOfRange,
56 "Too many items in collection".to_string(),
57 ))
58 })?;
59
60 let index: isize = input.parse()?;
62
63 let ret = if index < -len {
64 make_error!(IndexOutOfRange, "Too small index value");
66 } else if index < 0 {
67 len + index
69 } else if index == 0 {
70 make_error!(IndexOutOfRange, "Index value shouldn't be zero");
72 } else if index <= len {
73 index - 1
75 } else {
76 make_error!(IndexOutOfRange, "Too big index value");
78 };
79
80 Ok(ret as usize)
81}
82
83pub fn parse_obj<T: BufRead>(input: T) -> ObjResult<RawObj> {
85 let mut name = None;
86 let mut material_libraries = Vec::new();
87
88 let mut positions = Vec::new();
89 let mut tex_coords = Vec::new();
90 let mut normals = Vec::new();
91 let mut param_vertices = Vec::new();
92
93 let mut points = Vec::new();
94 let mut lines = Vec::new();
95 let mut polygons = Vec::new();
96
97 let counter = Counter::new(&points, &lines, &polygons);
98 let mut group_builder = GroupBuilder::with_default(&counter, String::from("default"));
99 let mut mesh_builder = GroupBuilder::with_default(&counter, String::new());
100 let mut smoothing_builder = GroupBuilder::new(&counter);
101 let mut merging_builder = GroupBuilder::new(&counter);
102
103 lex(input, |stmt, args: &[&str]| {
104 match stmt {
105 "v" => positions.push(match parse_args(args)?[..] {
107 [x, y, z, w] => (x, y, z, w),
108 [x, y, z] => (x, y, z, 1.0),
109 _ => make_error!(WrongNumberOfArguments, "Expected 3 or 4 arguments"),
110 }),
111 "vt" => tex_coords.push(match parse_args(args)?[..] {
112 [u, v, w] => (u, v, w),
113 [u, v] => (u, v, 0.0),
114 [u] => (u, 0.0, 0.0),
115 _ => make_error!(WrongNumberOfArguments, "Expected 1, 2 or 3 arguments"),
116 }),
117 "vn" => normals.push(match parse_args(args)?[..] {
118 [x, y, z] => (x, y, z),
119 _ => make_error!(WrongNumberOfArguments, "Expected 3 arguments"),
120 }),
121 "vp" => param_vertices.push(match parse_args(args)?[..] {
122 [u, v, w] => (u, v, w),
123 [u, v] => (u, v, 1.0),
124 [u] => (u, 0.0, 1.0),
125 _ => make_error!(WrongNumberOfArguments, "Expected 1, 2 or 3 arguments"),
126 }),
127
128 "cstype" => {
131 let geometry = match args {
132 ["rat", ty] => *ty,
133 [ty] => *ty,
134 _ => make_error!(WrongTypeOfArguments, "Expected 'rat xxx' or 'xxx' format"),
135 };
136
137 match geometry {
138 "bmatrix" => unimplemented!(),
139 "bezier" => unimplemented!(),
140 "bspline" => unimplemented!(),
141 "cardinal" => unimplemented!(),
142 "taylor" => unimplemented!(),
143 _ => make_error!(
144 WrongTypeOfArguments,
145 "Expected one of 'bmatrix', 'bezier', 'bspline', 'cardinal' and 'taylor'"
146 ),
147 }
148 }
149 "deg" => match parse_args(args)?[..] {
150 [_deg_u, _deg_v] => unimplemented!(),
151 [_deg_u] => unimplemented!(),
152 _ => make_error!(WrongNumberOfArguments, "Expected 1 or 2 arguments"),
153 },
154 "bmat" => unimplemented!(),
155 "step" => unimplemented!(),
156
157 "p" => {
159 for v in args {
160 let v = try_index(&positions, v)?;
161 points.push(v);
162 }
163 }
164 "l" => match args {
165 [] => make_error!(WrongNumberOfArguments, "Expected at least 2 arguments"),
166 [first, rest @ ..] => {
167 if args.len() < 2 {
168 make_error!(WrongNumberOfArguments, "Expected at least 2 arguments")
169 }
170
171 let line = parse_args! {
172 first, rest,
173 [p] => Line::P[try_index(&positions, p)?],
174 [p, t] => Line::PT[(try_index(&positions, p)?, try_index(&tex_coords, t)?)],
175 ! => make_error!(WrongTypeOfArguments, "Unexpected vertex format, expected `#`, or `#/#`")
176 };
177
178 lines.push(line);
179 }
180 },
181 "fo" | "f" => match args {
182 [] => make_error!(WrongNumberOfArguments, "Expected at least 3 arguments"),
183 [first, rest @ ..] => {
184 if args.len() < 3 {
185 make_error!(WrongNumberOfArguments, "Expected at least 3 arguments")
186 }
187
188 let polygon = parse_args! {
189 first, rest,
190 [p] => Polygon::P[try_index(&positions, p)?],
191 [p, t] => Polygon::PT[(try_index(&positions, p)?, try_index(&tex_coords, t)?)],
192 [p, "", n] => Polygon::PN[(try_index(&positions, p)?, try_index(&normals, n)?)],
193 [p, t, n] => Polygon::PTN[(try_index(&positions, p)?, try_index(&tex_coords, t)?, try_index(&normals, n)?)],
194 ! => make_error!(WrongTypeOfArguments, "Unexpected vertex format, expected `#`, `#/#`, `#//#`, or `#/#/#`")
195 };
196
197 polygons.push(polygon);
198 }
199 },
200 "curv" => unimplemented!(),
201 "curv2" => unimplemented!(),
202 "surf" => unimplemented!(),
203
204 "parm" => unimplemented!(),
206 "trim" => unimplemented!(),
207 "hole" => unimplemented!(),
208 "scrv" => unimplemented!(),
209 "sp" => unimplemented!(),
210 "end" => unimplemented!(),
211
212 "con" => unimplemented!(),
214
215 "g" => match args {
217 [name] => group_builder.start((*name).to_string()),
218 _ => make_error!(
219 WrongNumberOfArguments,
220 "Expected group name parameter, but nothing has been supplied"
221 ),
222 },
223 "s" => match args {
224 ["off"] | ["0"] => smoothing_builder.end(),
225 [param] => smoothing_builder.start(param.parse()?),
226 _ => make_error!(WrongNumberOfArguments, "Expected only 1 argument"),
227 },
228 "mg" => match args {
229 ["off"] | ["0"] => merging_builder.end(),
230 [param] => merging_builder.start(param.parse()?),
231 _ => make_error!(WrongNumberOfArguments, "Expected only 1 argument"),
232 },
233 "o" => {
234 name = match args {
235 [] => None,
236 _ => Some(args.join(" ")),
237 }
239 }
240
241 "bevel" => unimplemented!(),
243 "c_interp" => unimplemented!(),
244 "d_interp" => unimplemented!(),
245 "lod" => unimplemented!(),
246 "usemtl" => match args {
247 [material] => mesh_builder.start((*material).to_string()),
248 _ => make_error!(WrongNumberOfArguments, "Expected only 1 argument"),
249 },
250 "mtllib" => {
251 material_libraries.reserve(args.len());
252 for &path in args {
253 material_libraries.push(path.to_string());
254 }
255 }
256 "shadow_obj" => unimplemented!(),
257 "trace_obj" => unimplemented!(),
258 "ctech" => unimplemented!(),
259 "stech" => unimplemented!(),
260
261 _ => make_error!(UnexpectedStatement, "Received unknown statement"),
263 }
264
265 Ok(())
266 })?;
267
268 group_builder.end();
269 mesh_builder.end();
270 smoothing_builder.end();
271 merging_builder.end();
272
273 Ok(RawObj {
274 name,
275 material_libraries,
276
277 positions,
278 tex_coords,
279 normals,
280 param_vertices,
281
282 points,
283 lines,
284 polygons,
285
286 groups: group_builder.result,
287 meshes: mesh_builder.result,
288 smoothing_groups: smoothing_builder.result,
289 merging_groups: merging_builder.result,
290 })
291}
292
293fn split_vertex_group(input: &str) -> Vec<&str> {
295 input.split('/').collect()
296}
297
298struct Counter {
300 points: *const Vec<Point>,
301 lines: *const Vec<Line>,
302 polygons: *const Vec<Polygon>,
303}
304
305impl Counter {
306 fn new(
308 points: *const Vec<Point>,
309 lines: *const Vec<Line>,
310 polygons: *const Vec<Polygon>,
311 ) -> Self {
312 Counter {
313 points,
314 lines,
315 polygons,
316 }
317 }
318
319 fn get(&self) -> (usize, usize, usize) {
321 unsafe {
322 (
323 (*self.points).len(),
324 (*self.lines).len(),
325 (*self.polygons).len(),
326 )
327 }
328 }
329}
330
331struct GroupBuilder<'a, K> {
334 counter: &'a Counter,
335 current: Option<K>,
337 result: HashMap<K, Group>,
338}
339
340impl<'a, K> GroupBuilder<'a, K>
341where
342 K: Clone + Eq + Hash,
343{
344 fn new(counter: &'a Counter) -> Self {
345 GroupBuilder {
346 counter,
347 current: None,
348 result: HashMap::new(),
349 }
350 }
351
352 fn with_default(counter: &'a Counter, default: K) -> Self {
353 let mut result = HashMap::with_capacity(1);
354 result.insert(default.clone(), Group::new((0, 0, 0)));
355
356 GroupBuilder {
357 counter,
358 current: Some(default),
359 result,
360 }
361 }
362
363 fn start(&mut self, input: K) {
365 let count = self.counter.get();
366
367 match self.current {
368 Some(ref current) if *current == input => return,
370 Some(ref mut current) => {
372 let past = mem::replace(current, input.clone());
374 match self.result.entry(past) {
375 Entry::Vacant(_) => unreachable!(),
376 Entry::Occupied(mut e) => {
377 let was_empty_group = e.get_mut().end(count);
378 if was_empty_group {
380 e.remove();
381 }
382 }
383 }
384 }
385 None => self.current = Some(input.clone()),
387 }
388
389 self.result
390 .entry(input)
391 .and_modify(|e| e.start(count))
392 .or_insert_with(|| Group::new(count));
393 }
394
395 fn end(&mut self) {
397 match self.current.take() {
398 None => {}
400 Some(current) => {
402 match self.result.entry(current) {
403 Entry::Vacant(_) => unreachable!(),
404 Entry::Occupied(mut e) => {
405 let count = self.counter.get();
406 let was_empty_group = e.get_mut().end(count);
407 if was_empty_group {
409 e.remove();
410 }
411 }
412 }
413 }
414 }
415 }
416}
417
418const UNDEFINED: usize = usize::MAX;
420
421impl Group {
422 fn new(count: (usize, usize, usize)) -> Self {
423 let mut ret = Group {
424 points: Vec::with_capacity(1),
425 lines: Vec::with_capacity(1),
426 polygons: Vec::with_capacity(1),
427 };
428 ret.start(count);
429 ret
430 }
431
432 fn start(&mut self, count: (usize, usize, usize)) {
433 self.points.push(Range {
434 start: count.0,
435 end: UNDEFINED,
436 });
437 self.lines.push(Range {
438 start: count.1,
439 end: UNDEFINED,
440 });
441 self.polygons.push(Range {
442 start: count.2,
443 end: UNDEFINED,
444 })
445 }
446
447 fn end(&mut self, count: (usize, usize, usize)) -> bool {
449 end(&mut self.points, count.0);
450 end(&mut self.lines, count.1);
451 end(&mut self.polygons, count.2);
452
453 fn end(vec: &mut Vec<Range>, end: usize) {
454 let last = vec.len() - 1;
455 assert_eq!(vec[last].end, UNDEFINED);
456 if vec[last].start != end {
457 vec[last].end = end;
458 } else {
459 vec.pop();
460 }
461 }
462
463 self.points.is_empty() && self.lines.is_empty() && self.polygons.is_empty()
464 }
465}
466
467#[derive(Clone, PartialEq, Debug, Default)]
469pub struct RawObj {
470 pub name: Option<String>,
472 pub material_libraries: Vec<String>,
474
475 pub positions: Vec<(f32, f32, f32, f32)>,
477 pub tex_coords: Vec<(f32, f32, f32)>,
479 pub normals: Vec<(f32, f32, f32)>,
481 pub param_vertices: Vec<(f32, f32, f32)>,
483
484 pub points: Vec<Point>,
486 pub lines: Vec<Line>,
488 pub polygons: Vec<Polygon>,
490
491 pub groups: HashMap<String, Group>,
493 pub meshes: HashMap<String, Group>,
495 pub smoothing_groups: HashMap<usize, Group>,
497 pub merging_groups: HashMap<usize, Group>,
499}
500
501pub type Point = usize;
503
504#[derive(Clone, Eq, PartialEq, Hash, Debug)]
506pub enum Line {
507 P(Vec<usize>),
509 PT(Vec<(usize, usize)>),
512}
513
514#[derive(Clone, Eq, PartialEq, Hash, Debug)]
516pub enum Polygon {
517 P(Vec<usize>),
519 PT(Vec<(usize, usize)>),
521 PN(Vec<(usize, usize)>),
523 PTN(Vec<(usize, usize, usize)>),
525}
526
527#[derive(Clone, Eq, PartialEq, Hash, Debug, Default)]
529pub struct Group {
530 pub points: Vec<Range>,
532 pub lines: Vec<Range>,
534 pub polygons: Vec<Range>,
536}
537
538#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
540pub struct Range {
541 pub start: usize,
543 pub end: usize,
545}