mesh_loader/
common.rs

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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
use std::{fmt, path::PathBuf};

pub(crate) type Vec2 = [f32; 2];
pub(crate) type Vec3 = [f32; 3];
pub(crate) type Face = [u32; 3];
pub(crate) type Color4 = [f32; 4];

// TODO: assimp uses 8 here
pub(crate) const MAX_NUMBER_OF_TEXCOORDS: usize = 2;
// TODO: assimp uses 8 here
pub(crate) const MAX_NUMBER_OF_COLOR_SETS: usize = 2;

#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct Scene {
    pub materials: Vec<Material>,
    pub meshes: Vec<Mesh>,
}

/// Triangle mesh
#[derive(Clone, Default)]
#[non_exhaustive]
pub struct Mesh {
    pub name: String,
    pub vertices: Vec<Vec3>,
    // TODO: use Vec3?
    pub texcoords: [Vec<Vec2>; MAX_NUMBER_OF_TEXCOORDS],
    pub normals: Vec<Vec3>,
    pub faces: Vec<Face>,
    pub colors: [Vec<Color4>; MAX_NUMBER_OF_COLOR_SETS],
    #[cfg(feature = "obj")]
    pub(crate) material_index: u32,
}

impl Mesh {
    #[inline]
    #[must_use]
    pub fn merge(mut meshes: Vec<Self>) -> Self {
        if meshes.len() <= 1 {
            return meshes.pop().unwrap_or_default();
        }

        let num_vertices = meshes.iter().map(|m| m.vertices.len()).sum();
        let mut vertices = Vec::with_capacity(num_vertices);
        let mut normals = Vec::with_capacity(num_vertices);
        // TODO: fill with default if one or more meshes has colors
        let has_colors0 = num_vertices == meshes.iter().map(|m| m.colors[0].len()).sum();
        let mut colors0 = Vec::with_capacity(if has_colors0 { num_vertices } else { 0 });
        let has_colors1 = num_vertices == meshes.iter().map(|m| m.colors[1].len()).sum();
        let mut colors1 = Vec::with_capacity(if has_colors1 { num_vertices } else { 0 });
        for m in &meshes {
            vertices.extend_from_slice(&m.vertices);
            normals.extend_from_slice(&m.normals);
            if has_colors0 {
                colors0.extend_from_slice(&m.colors[0]);
            }
            if has_colors1 {
                colors1.extend_from_slice(&m.colors[1]);
            }
        }
        let mut faces = Vec::with_capacity(meshes.iter().map(|m| m.faces.len()).sum());
        let mut last = 0;
        for m in &meshes {
            if m.faces.is_empty() {
                continue;
            }
            faces.extend(
                m.faces
                    .iter()
                    .map(|f| [f[0] + last, f[1] + last, f[2] + last]),
            );
            last = m.faces.last().unwrap()[2] + 1;
        }

        Self {
            name: String::new(),
            vertices,
            texcoords: Default::default(), // TODO
            normals,
            faces,
            colors: [colors0, colors1],
            #[cfg(feature = "obj")]
            material_index: u32::MAX,
        }
    }
}

impl fmt::Debug for Mesh {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Mesh")
            .field("name", &self.name)
            .field("num_vertices", &self.vertices.len())
            .field("num_texcoords0", &self.texcoords[0].len())
            .field("num_texcoords1", &self.texcoords[1].len())
            .field("num_normals", &self.normals.len())
            .field("num_faces", &self.faces.len())
            .field("num_colors0", &self.colors[0].len())
            .field("num_colors1", &self.colors[1].len())
            .finish_non_exhaustive()
    }
}

#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct Material {
    // Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L944-L955
    pub name: String,
    pub shading_model: Option<ShadingModel>,
    pub opacity: Option<f32>,
    pub shininess: Option<f32>,
    pub reflectivity: Option<f32>,
    pub index_of_refraction: Option<f32>,

    pub color: Colors,
    pub texture: Textures,
}

// Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L956-L961
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct Colors {
    pub diffuse: Option<Color4>,
    pub ambient: Option<Color4>,
    pub specular: Option<Color4>,
    pub emissive: Option<Color4>,
    pub transparent: Option<Color4>,
    pub reflective: Option<Color4>,
}

// Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L188
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct Textures {
    pub diffuse: Option<PathBuf>,
    pub specular: Option<PathBuf>,
    pub ambient: Option<PathBuf>,
    pub emissive: Option<PathBuf>,
    pub height: Option<PathBuf>,
    pub normal: Option<PathBuf>,
    pub shininess: Option<PathBuf>,
    pub opacity: Option<PathBuf>,
    pub displacement: Option<PathBuf>,
    pub lightmap: Option<PathBuf>,
    pub reflection: Option<PathBuf>,
}

// Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L355
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum ShadingModel {
    Flat,
    Gouraud,
    Phong,
    Blinn,
    NoShading,
}