nobject_rs/
model.rs

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/// A wrapper for an underlying error which occurred
21/// while parsing the token stream.
22#[derive(Error, Debug)]
23pub enum ModelError {
24    #[error("Parse Error: `{0}`")]
25    Parse(String),
26}
27
28/// Representation of vertex data. The w component is optional.
29#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
30pub struct Vertex {
31    /// X coordinate
32    pub x: f32,
33    /// Y coordinate
34    pub y: f32,
35    /// Z coordinate
36    pub z: f32,
37    /// Optional W coordinate
38    pub w: Option<f32>,
39}
40
41/// Representation of normal data.
42#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
43pub struct Normal {
44    /// X coordinate
45    pub x: f32,
46    /// Y coordinate
47    pub y: f32,
48    /// Z coordinate
49    pub z: f32,
50}
51
52/// Representation of texture data. v/w are optional.
53#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
54pub struct Texture {
55    /// U coordinate
56    pub u: f32,
57    /// Optional V coordinate
58    pub v: Option<f32>,
59    /// Optional W coordinate
60    pub w: Option<f32>,
61}
62
63/// Defines the settings that get applied to a group of faces.
64#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
65pub struct Group {
66    /// The name of the material to apply to the group.
67    pub material_name: String,
68    /// Bevel interpolation setting.
69    pub bevel: bool,
70    /// Color interpolation setting.
71    pub c_interp: bool,
72    /// Disolve interpolation setting.
73    pub d_interp: bool,
74    /// Level of detail setting.
75    pub lod: u8,
76    /// The name of the texture map file.
77    pub texture_map: Option<String>,
78}
79
80/// Holds the vertex/texture/normal indicies for a part of a face.
81#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
82pub struct FaceElement {
83    /// Vertex index. Note that these START at 1, NOT 0.
84    pub vertex_index: i32,
85    /// Optional texture index. Note that these START at 1, NOT 0.
86    pub texture_index: Option<i32>,
87    /// Optional normal index. Note that these START at 1, NOT 0.
88    pub normal_index: Option<i32>,
89}
90
91/// The primary purpose is to store the collection of
92/// elements (vertices/normals/texture coordinates) that
93/// compose a face. This also contains a smoothing group
94/// identifier, as specified by the obj file.
95#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
96pub struct Face {
97    /// Collection of `FaceElement`.
98    pub elements: Vec<FaceElement>,
99    /// The smoothing group identifier.
100    pub smoothing_group: i32,
101}
102
103/// Contains the indicies for a line element.
104#[derive(Copy, Clone, Constructor, Debug, Default, From, Into, PartialEq)]
105pub struct LineElement {
106    /// Vertex index. Note that these START at 1, NOT 0.
107    pub vertex_index: i32,
108    /// Optional texture index. Note that these START at 1, NOT 0.
109    pub texture_index: Option<i32>,
110}
111
112/// Contains the set of elements which compose a line.
113#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
114pub struct Line {
115    /// Set of line elements.
116    pub elements: Vec<LineElement>,
117}
118
119/// Contains a set of id's for the verticies which compose the point collection.
120#[derive(Clone, Constructor, Debug, Default, From, Into, PartialEq)]
121pub struct Point {
122    /// Set of vertex indices. Note that these START at 1, NOT 0.
123    pub elements: Vec<i32>,
124}
125
126/// This holds the end result of parsing an obj file.
127/// The default group for all models is "default".
128/// That is to say, if no group is defined in a file,
129/// a "default" group will be used.  
130///
131/// Everything will fall under the "default" group until another group
132/// is specified.
133#[derive(Clone, Debug, From, Into)]
134pub struct Model {
135    /// Collection of vertex data
136    pub vertices: Vec<Vertex>,
137    // Collection of normal data
138    pub normals: Vec<Normal>,
139    /// Collection of texture coordinate data
140    pub textures: Vec<Texture>,
141    /// A map of group name to a collection of faces which belong to the group
142    /// Everything will fall under the "default" group until another group
143    /// is specified.
144    pub faces: HashMap<String, Vec<Face>>,
145    /// A map of group name to a collection of lines.
146    /// Everything will fall under the "default" group until another group
147    /// is specified.
148    pub lines: HashMap<String, Vec<Line>>,
149    /// A map of group name to a collection of points.
150    /// Everything will fall under the "default" group until another group
151    /// is specified.
152    pub points: HashMap<String, Vec<Point>>,
153    /// A map of group name to the groups specific data.
154    /// Everything will fall under the "default" group until another group
155    /// is specified.
156    pub groups: HashMap<String, Group>,
157    /// The material library files to use with this obj.
158    pub material_libs: Vec<String>,
159    /// The texture library files to use with this obj.
160    pub texture_libs: Vec<String>,
161    /// The file name for the shadow object
162    pub shadow_obj: Option<String>,
163    /// The file name for the ray trace object
164    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}