1use std::{collections::HashMap, result::Result};
2
3use derive_more::{Constructor, From, Into};
4
5use crate::{
6 get_on_off_from_str, get_token_float, get_token_int, get_token_string,
7 tokenizer::{Token, TokenSet},
8};
9
10use nom::{
11 branch::alt,
12 combinator::{map, opt},
13 error,
14 multi::{fold_many0, fold_many1, many1},
15 sequence::preceded,
16 IResult, Parser,
17};
18use thiserror::Error;
19
20#[derive(Error, Debug)]
23pub enum ModelError {
24 #[error("Parse Error: `{0}`")]
25 Parse(String),
26}
27
28#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
30pub struct Vertex {
31 pub x: f32,
33 pub y: f32,
35 pub z: f32,
37 pub w: Option<f32>,
39}
40
41#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
43pub struct Normal {
44 pub x: f32,
46 pub y: f32,
48 pub z: f32,
50}
51
52#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
54pub struct Texture {
55 pub u: f32,
57 pub v: Option<f32>,
59 pub w: Option<f32>,
61}
62
63#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
65pub struct Group {
66 pub material_name: String,
68 pub bevel: bool,
70 pub c_interp: bool,
72 pub d_interp: bool,
74 pub lod: u8,
76 pub texture_map: Option<String>,
78}
79
80#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
82pub struct FaceElement {
83 pub vertex_index: i32,
85 pub texture_index: Option<i32>,
87 pub normal_index: Option<i32>,
89}
90
91#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
96pub struct Face {
97 pub elements: Vec<FaceElement>,
99 pub smoothing_group: i32,
101}
102
103#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
105pub struct LineElement {
106 pub vertex_index: i32,
108 pub texture_index: Option<i32>,
110}
111
112#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
114pub struct Line {
115 pub elements: Vec<LineElement>,
117}
118
119#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
121pub struct Point {
122 pub elements: Vec<i32>,
124}
125
126#[derive(Clone, Debug, From, Into)]
134pub struct Model {
135 pub vertices: Vec<Vertex>,
137 pub normals: Vec<Normal>,
139 pub textures: Vec<Texture>,
141 pub faces: HashMap<String, Vec<Face>>,
145 pub lines: HashMap<String, Vec<Line>>,
149 pub points: HashMap<String, Vec<Point>>,
153 pub groups: HashMap<String, Group>,
157 pub material_libs: Vec<String>,
159 pub texture_libs: Vec<String>,
161 pub shadow_obj: Option<String>,
163 pub trace_obj: Option<String>,
165
166 current_group: Vec<String>,
167 current_smoothing_group: i32,
168}
169
170impl Default for Model {
171 fn default() -> Self {
172 Self {
173 vertices: Default::default(),
174 normals: Default::default(),
175 textures: Default::default(),
176 faces: Default::default(),
177 lines: Default::default(),
178 points: Default::default(),
179 groups: {
180 let mut res = HashMap::new();
181 res.insert("default".into(), Default::default());
182 res
183 },
184 material_libs: Default::default(),
185 texture_libs: Default::default(),
186 shadow_obj: Default::default(),
187 trace_obj: Default::default(),
188 current_group: vec!["default".into()],
189 current_smoothing_group: 0,
190 }
191 }
192}
193
194#[derive(Clone, Debug, PartialEq)]
195pub(crate) enum ModelElement {
196 Vertex(Vertex),
197 Normal(Normal),
198 Texture(Texture),
199 Face(Face),
200 Line(Line),
201 Point(Point),
202 Group(Vec<String>),
203 MaterialLib(Vec<String>),
204 Material(String),
205 ObjName(String),
206 Smoothing(i32),
207 Bevel(bool),
208 CInterp(bool),
209 DInterp(bool),
210 Lod(i32),
211 ShadowObj(String),
212 TraceObj(String),
213 TextureLib(Vec<String>),
214 TextureMap(String),
215}
216
217pub(crate) fn parse(input: TokenSet) -> Result<Model, ModelError> {
218 match fold_many0(
219 alt((
220 map(parse_vertex(), ModelElement::Vertex),
221 map(parse_vertex_normal(), ModelElement::Normal),
222 map(parse_vertex_texture(), ModelElement::Texture),
223 map(parse_face(), ModelElement::Face),
224 map(parse_line(), ModelElement::Line),
225 map(parse_point(), ModelElement::Point),
226 parse_mat_lib(),
227 parse_material(),
228 parse_obj_name(),
229 parse_smoothing(),
230 parse_bevel(),
231 parse_c_interp(),
232 parse_d_interp(),
233 parse_lod(),
234 parse_shadow_obj(),
235 parse_trace_obj(),
236 parse_texture_lib(),
237 parse_texture_map(),
238 parse_group(),
239 )),
240 Model::default,
241 |mut model: Model, item: ModelElement| {
242 match item {
243 ModelElement::Vertex(x) => model.vertices.push(x),
244 ModelElement::Normal(n) => model.normals.push(n),
245 ModelElement::Texture(t) => model.textures.push(t),
246 ModelElement::Face(mut f) => {
247 f.smoothing_group = model.current_smoothing_group;
248 for g in &model.current_group {
249 let set = model.faces.entry(g.clone()).or_default();
250 set.push(f.clone());
251 }
252 },
253 ModelElement::Line(l) => {
254 for g in &model.current_group {
255 let set = model.lines.entry(g.clone()).or_default();
256 set.push(l.clone());
257 }
258 },
259 ModelElement::Point(p) => {
260 for g in &model.current_group {
261 let set = model.points.entry(g.clone()).or_default();
262 set.push(p.clone());
263 }
264 },
265 ModelElement::Group(groups) => {
266 model.current_group.clear();
267 for g in groups {
268 model.groups.insert(g.clone(), Default::default());
269 model.current_group.push(g);
270 }
271 },
272 ModelElement::MaterialLib(libs) => model.material_libs.extend(libs),
273 ModelElement::Material(name) => {
274 for g in &model.current_group {
275 let group = model.groups.entry(g.clone()).or_default();
276 group.material_name = name.clone();
277 }
278 },
279 ModelElement::ObjName(_name) => {},
280 ModelElement::Smoothing(group_id) => {
281 model.current_smoothing_group = group_id;
282 },
283 ModelElement::Bevel(_flag) => {},
284 ModelElement::CInterp(_flag) => {},
285 ModelElement::DInterp(_flag) => {},
286 ModelElement::Lod(_level) => {},
287 ModelElement::ShadowObj(_name) => {},
288 ModelElement::TraceObj(_name) => {},
289 ModelElement::TextureLib(libs) => {
290 model.texture_libs.extend(libs);
291 },
292 ModelElement::TextureMap(name) => {
293 for g in &model.current_group {
294 let group = model.groups.entry(g.clone()).or_default();
295 group.texture_map = Some(name.clone());
296 }
297 },
298 }
299 model
300 },
301 )
302 .parse_complete(input)
303 {
304 Ok((_, acc)) => Ok(acc),
305 Err(e) => Err(ModelError::Parse(e.to_string())),
306 }
307}
308
309pub(crate) fn parse_vertex<'a>(
310) -> impl Parser<TokenSet<'a>, Output = Vertex, Error = error::Error<TokenSet<'a>>> {
311 map(
312 preceded(
313 token_match!(Token::Vertex),
314 (
315 token_match!(Token::Float(_) | Token::Int(_)),
316 token_match!(Token::Float(_) | Token::Int(_)),
317 token_match!(Token::Float(_) | Token::Int(_)),
318 opt(token_match!(Token::Float(_) | Token::Int(_))),
319 ),
320 ),
321 |(x, y, z, w)| {
322 let (x, y, z) = (
323 match get_token_float(&x) {
324 Ok(s) => s,
325 Err(e) => {
326 log::error!("{}", e);
327 Default::default()
328 },
329 },
330 match get_token_float(&y) {
331 Ok(s) => s,
332 Err(e) => {
333 log::error!("{}", e);
334 Default::default()
335 },
336 },
337 match get_token_float(&z) {
338 Ok(s) => s,
339 Err(e) => {
340 log::error!("{}", e);
341 Default::default()
342 },
343 },
344 );
345 let w = w.map(|val| match get_token_float(&val) {
346 Ok(s) => s,
347 Err(e) => {
348 log::error!("{}", e);
349 Default::default()
350 },
351 });
352 (x, y, z, w).into()
353 },
354 )
355}
356
357pub(crate) fn parse_vertex_normal<'a>(
358) -> impl Parser<TokenSet<'a>, Output = Normal, Error = error::Error<TokenSet<'a>>> {
359 map(
360 preceded(
361 token_match!(Token::VertexNormal),
362 (
363 token_match!(Token::Float(_) | Token::Int(_)),
364 token_match!(Token::Float(_) | Token::Int(_)),
365 token_match!(Token::Float(_) | Token::Int(_)),
366 ),
367 ),
368 |(x, y, z)| {
369 let (x, y, z) = (
370 match get_token_float(&x) {
371 Ok(s) => s,
372 Err(e) => {
373 log::error!("{}", e);
374 Default::default()
375 },
376 },
377 match get_token_float(&y) {
378 Ok(s) => s,
379 Err(e) => {
380 log::error!("{}", e);
381 Default::default()
382 },
383 },
384 match get_token_float(&z) {
385 Ok(s) => s,
386 Err(e) => {
387 log::error!("{}", e);
388 Default::default()
389 },
390 },
391 );
392 (x, y, z).into()
393 },
394 )
395}
396
397pub(crate) fn parse_vertex_texture<'a>(
398) -> impl Parser<TokenSet<'a>, Output = Texture, Error = error::Error<TokenSet<'a>>> {
399 map(
400 preceded(
401 token_match!(Token::VertexTexture),
402 (
403 token_match!(Token::Float(_) | Token::Int(_)),
404 opt(token_match!(Token::Float(_) | Token::Int(_))),
405 opt(token_match!(Token::Float(_) | Token::Int(_))),
406 ),
407 ),
408 |(u, v, w)| {
409 let u = match get_token_float(&u) {
410 Ok(s) => s,
411 Err(e) => {
412 log::error!("{}", e);
413 Default::default()
414 },
415 };
416 let v = v.map(|val| match get_token_float(&val) {
417 Ok(s) => s,
418 Err(e) => {
419 log::error!("{}", e);
420 Default::default()
421 },
422 });
423 let w = w.map(|val| match get_token_float(&val) {
424 Ok(s) => s,
425 Err(e) => {
426 log::error!("{}", e);
427 Default::default()
428 },
429 });
430 (u, v, w).into()
431 },
432 )
433}
434
435pub(crate) fn parse_face<'a>(
436) -> impl Parser<TokenSet<'a>, Output = Face, Error = error::Error<TokenSet<'a>>> {
437 preceded(
438 token_match!(Token::Face),
439 fold_many1(
440 map(
441 (
442 token_match!(Token::Int(_)),
443 opt(preceded(
444 token_match!(Token::Slash),
445 opt(token_match!(Token::Int(_))),
446 )),
447 opt(preceded(
448 token_match!(Token::Slash),
449 opt(token_match!(Token::Int(_))),
450 )),
451 ),
452 |(v, t, n)| {
453 let v = match get_token_int(&v) {
454 Ok(s) => s,
455 Err(e) => {
456 log::error!("{}", e);
457 Default::default()
458 },
459 };
460 let t = match t {
461 Some(t) => t.map(|tex| match get_token_int(&tex) {
462 Ok(s) => s,
463 Err(e) => {
464 log::error!("{}", e);
465 Default::default()
466 },
467 }),
468 None => None,
469 };
470
471 let n = match n {
472 Some(n) => n.map(|norm| match get_token_int(&norm) {
473 Ok(s) => s,
474 Err(e) => {
475 log::error!("{}", e);
476 Default::default()
477 },
478 }),
479 None => None,
480 };
481 (v, t, n).into()
482 },
483 ),
484 Face::default,
485 |mut f: Face, item: FaceElement| {
486 f.elements.push(item);
487 f
488 },
489 ),
490 )
491}
492
493pub(crate) fn parse_line<'a>(
494) -> impl Parser<TokenSet<'a>, Output = Line, Error = error::Error<TokenSet<'a>>> {
495 preceded(
496 token_match!(Token::Line),
497 fold_many1(
498 map(
499 (
500 token_match!(Token::Int(_)),
501 opt(preceded(
502 token_match!(Token::Slash),
503 opt(token_match!(Token::Int(_))),
504 )),
505 ),
506 |(v, t)| {
507 let v = match get_token_int(&v) {
508 Ok(s) => s,
509 Err(e) => {
510 log::error!("{}", e);
511 Default::default()
512 },
513 };
514 let t = t.flatten().map(|tex| match get_token_int(&tex) {
515 Ok(s) => s,
516 Err(e) => {
517 log::error!("{}", e);
518 Default::default()
519 },
520 });
521 (v, t).into()
522 },
523 ),
524 Line::default,
525 |mut f: Line, item: LineElement| {
526 f.elements.push(item);
527 f
528 },
529 ),
530 )
531}
532
533pub(crate) fn parse_point<'a>(
534) -> impl Parser<TokenSet<'a>, Output = Point, Error = error::Error<TokenSet<'a>>> {
535 preceded(
536 token_match!(Token::Point),
537 fold_many1(
538 map(token_match!(Token::Int(_)), |v| match get_token_int(&v) {
539 Ok(s) => s,
540 Err(e) => {
541 log::error!("{}", e);
542 Default::default()
543 },
544 }),
545 Point::default,
546 |mut f: Point, item: i32| {
547 f.elements.push(item);
548 f
549 },
550 ),
551 )
552}
553
554pub(crate) fn parse_group<'a>(
555) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
556 map(
557 preceded(
558 token_match!(Token::Group),
559 many1(map(
560 token_match!(Token::String(_)),
561 |s| match get_token_string(&s) {
562 Ok(s) => s.into(),
563 Err(e) => {
564 log::error!("{}", e);
565 Default::default()
566 },
567 },
568 )),
569 ),
570 ModelElement::Group,
571 )
572}
573
574pub(crate) fn parse_mat_lib<'a>(
575) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
576 map(
577 preceded(
578 token_match!(Token::MaterialLib),
579 many1(map(
580 token_match!(Token::String(_)),
581 |s| match get_token_string(&s) {
582 Ok(s) => s.into(),
583 Err(e) => {
584 log::error!("{}", e);
585 Default::default()
586 },
587 },
588 )),
589 ),
590 ModelElement::MaterialLib,
591 )
592}
593
594pub(crate) fn parse_material<'a>(
595) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
596 map(
597 preceded(
598 token_match!(Token::UseMaterial),
599 token_match!(Token::String(_)),
600 ),
601 |s| {
602 let res = match get_token_string(&s) {
603 Ok(s) => s,
604 Err(e) => {
605 log::error!("{}", e);
606 Default::default()
607 },
608 };
609
610 ModelElement::Material(res.into())
611 },
612 )
613}
614
615pub(crate) fn parse_obj_name<'a>(
616) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
617 map(
618 preceded(
619 token_match!(Token::Object),
620 token_match!(Token::String(_) | Token::Int(_)),
621 ),
622 |s| {
623 let res = match get_token_string(&s) {
624 Ok(s) => s,
625 Err(e) => {
626 log::error!("{}", e);
627 Default::default()
628 },
629 };
630 ModelElement::ObjName(res.into())
631 },
632 )
633}
634
635pub(crate) fn parse_smoothing<'a>(
636) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
637 map(
638 preceded(
639 token_match!(Token::Smoothing),
640 alt((
641 token_match!(Token::Int(_)),
642 map(token_match!(Token::String(_)), |s| {
643 let val = match get_on_off_from_str(&s) {
644 Ok(v) => v,
645 Err(e) => {
646 log::error!("{}", e);
647 Default::default()
648 },
649 };
650 if !val {
651 Token::Int(0)
652 } else {
653 log::error!("Invalid smoothing value encountered. Setting default to 1.");
654 Token::Int(1)
655 }
656 }),
657 )),
658 ),
659 |s| {
660 let res = match get_token_int(&s) {
661 Ok(s) => s,
662 Err(e) => {
663 log::error!("{}", e);
664 Default::default()
665 },
666 };
667 ModelElement::Smoothing(res)
668 },
669 )
670}
671
672pub(crate) fn parse_bevel<'a>(
673) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
674 map(
675 preceded(token_match!(Token::Bevel), token_match!(Token::String(_))),
676 |s| {
677 let res = match get_token_string(&s) {
678 Ok(s) => s,
679 Err(e) => {
680 log::error!("{}", e);
681 Default::default()
682 },
683 };
684
685 if let Ok(flag) = res.parse::<bool>() {
686 ModelElement::Bevel(flag)
687 } else {
688 ModelElement::Bevel(false)
689 }
690 },
691 )
692}
693
694pub(crate) fn parse_c_interp<'a>(
695) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
696 map(
697 preceded(token_match!(Token::CInterp), token_match!(Token::String(_))),
698 |s| {
699 let res = match get_token_string(&s) {
700 Ok(s) => s,
701 Err(e) => {
702 log::error!("{}", e);
703 Default::default()
704 },
705 };
706
707 if let Ok(flag) = res.parse::<bool>() {
708 ModelElement::CInterp(flag)
709 } else {
710 ModelElement::CInterp(false)
711 }
712 },
713 )
714}
715
716pub(crate) fn parse_d_interp<'a>(
717) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
718 map(
719 preceded(token_match!(Token::DInterp), token_match!(Token::String(_))),
720 |s| {
721 let res = match get_token_string(&s) {
722 Ok(s) => s,
723 Err(e) => {
724 log::error!("{}", e);
725 Default::default()
726 },
727 };
728
729 if let Ok(flag) = res.parse::<bool>() {
730 ModelElement::DInterp(flag)
731 } else {
732 ModelElement::DInterp(false)
733 }
734 },
735 )
736}
737
738pub(crate) fn parse_lod<'a>(
739) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
740 map(
741 preceded(token_match!(Token::Lod), token_match!(Token::Int(_))),
742 |s| {
743 let res = match get_token_int(&s) {
744 Ok(s) => s,
745 Err(e) => {
746 log::error!("{}", e);
747 Default::default()
748 },
749 };
750 ModelElement::Lod(res)
751 },
752 )
753}
754
755pub(crate) fn parse_shadow_obj<'a>(
756) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
757 map(
758 preceded(
759 token_match!(Token::ShadowObj),
760 token_match!(Token::String(_)),
761 ),
762 |s| {
763 let res = match get_token_string(&s) {
764 Ok(s) => s,
765 Err(e) => {
766 log::error!("{}", e);
767 Default::default()
768 },
769 };
770
771 ModelElement::ShadowObj(res.into())
772 },
773 )
774}
775
776pub(crate) fn parse_trace_obj<'a>(
777) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
778 map(
779 preceded(
780 token_match!(Token::TraceObj),
781 token_match!(Token::String(_)),
782 ),
783 |s| {
784 let res = match get_token_string(&s) {
785 Ok(s) => s,
786 Err(e) => {
787 log::error!("{}", e);
788 Default::default()
789 },
790 };
791
792 ModelElement::TraceObj(res.into())
793 },
794 )
795}
796
797pub(crate) fn parse_texture_lib<'a>(
798) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
799 map(
800 preceded(
801 token_match!(Token::TextureMapLib),
802 many1(map(token_match!(Token::String(_)), |s| {
803 let res = match get_token_string(&s) {
804 Ok(s) => s,
805 Err(e) => {
806 log::error!("{}", e);
807 Default::default()
808 },
809 };
810
811 res.into()
812 })),
813 ),
814 ModelElement::TextureLib,
815 )
816}
817
818pub(crate) fn parse_texture_map<'a>(
819) -> impl Parser<TokenSet<'a>, Output = ModelElement, Error = error::Error<TokenSet<'a>>> {
820 map(
821 preceded(
822 token_match!(Token::UseTextureMap),
823 token_match!(Token::String(_)),
824 ),
825 |s| {
826 let res = match get_token_string(&s) {
827 Ok(s) => s,
828 Err(e) => {
829 log::error!("{}", e);
830 Default::default()
831 },
832 };
833
834 ModelElement::TextureMap(res.into())
835 },
836 )
837}