mesh_loader/
common.rs

1use std::{fmt, path::PathBuf};
2
3pub(crate) type Vec2 = [f32; 2];
4pub(crate) type Vec3 = [f32; 3];
5pub(crate) type Face = [u32; 3];
6pub(crate) type Color4 = [f32; 4];
7
8// TODO: assimp uses 8 here
9pub(crate) const MAX_NUMBER_OF_TEXCOORDS: usize = 2;
10// TODO: assimp uses 8 here
11pub(crate) const MAX_NUMBER_OF_COLOR_SETS: usize = 2;
12
13#[derive(Debug, Clone, Default)]
14#[non_exhaustive]
15pub struct Scene {
16    pub materials: Vec<Material>,
17    pub meshes: Vec<Mesh>,
18}
19
20/// Triangle mesh
21#[derive(Clone, Default)]
22#[non_exhaustive]
23pub struct Mesh {
24    pub name: String,
25    pub vertices: Vec<Vec3>,
26    // TODO: use Vec3?
27    pub texcoords: [Vec<Vec2>; MAX_NUMBER_OF_TEXCOORDS],
28    pub normals: Vec<Vec3>,
29    pub faces: Vec<Face>,
30    pub colors: [Vec<Color4>; MAX_NUMBER_OF_COLOR_SETS],
31    #[cfg(feature = "obj")]
32    pub(crate) material_index: u32,
33}
34
35impl Mesh {
36    #[inline]
37    #[must_use]
38    pub fn merge(mut meshes: Vec<Self>) -> Self {
39        if meshes.len() <= 1 {
40            return meshes.pop().unwrap_or_default();
41        }
42
43        let num_vertices = meshes.iter().map(|m| m.vertices.len()).sum();
44        let mut vertices = Vec::with_capacity(num_vertices);
45        let mut normals = Vec::with_capacity(num_vertices);
46        // TODO: fill with default if one or more meshes has colors
47        let has_colors0 = num_vertices == meshes.iter().map(|m| m.colors[0].len()).sum();
48        let mut colors0 = Vec::with_capacity(if has_colors0 { num_vertices } else { 0 });
49        let has_colors1 = num_vertices == meshes.iter().map(|m| m.colors[1].len()).sum();
50        let mut colors1 = Vec::with_capacity(if has_colors1 { num_vertices } else { 0 });
51        for m in &meshes {
52            vertices.extend_from_slice(&m.vertices);
53            normals.extend_from_slice(&m.normals);
54            if has_colors0 {
55                colors0.extend_from_slice(&m.colors[0]);
56            }
57            if has_colors1 {
58                colors1.extend_from_slice(&m.colors[1]);
59            }
60        }
61        let mut faces = Vec::with_capacity(meshes.iter().map(|m| m.faces.len()).sum());
62        let mut last = 0;
63        for m in &meshes {
64            if m.faces.is_empty() {
65                continue;
66            }
67            faces.extend(
68                m.faces
69                    .iter()
70                    .map(|f| [f[0] + last, f[1] + last, f[2] + last]),
71            );
72            last = m.faces.last().unwrap()[2] + 1;
73        }
74
75        Self {
76            name: String::new(),
77            vertices,
78            texcoords: Default::default(), // TODO
79            normals,
80            faces,
81            colors: [colors0, colors1],
82            #[cfg(feature = "obj")]
83            material_index: u32::MAX,
84        }
85    }
86}
87
88impl fmt::Debug for Mesh {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        f.debug_struct("Mesh")
91            .field("name", &self.name)
92            .field("num_vertices", &self.vertices.len())
93            .field("num_texcoords0", &self.texcoords[0].len())
94            .field("num_texcoords1", &self.texcoords[1].len())
95            .field("num_normals", &self.normals.len())
96            .field("num_faces", &self.faces.len())
97            .field("num_colors0", &self.colors[0].len())
98            .field("num_colors1", &self.colors[1].len())
99            .finish_non_exhaustive()
100    }
101}
102
103#[derive(Debug, Clone, Default)]
104#[non_exhaustive]
105pub struct Material {
106    // Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L944-L955
107    pub name: String,
108    pub shading_model: Option<ShadingModel>,
109    pub opacity: Option<f32>,
110    pub shininess: Option<f32>,
111    pub reflectivity: Option<f32>,
112    pub index_of_refraction: Option<f32>,
113
114    pub color: Colors,
115    pub texture: Textures,
116}
117
118// Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L956-L961
119#[derive(Debug, Clone, Default)]
120#[non_exhaustive]
121pub struct Colors {
122    pub diffuse: Option<Color4>,
123    pub ambient: Option<Color4>,
124    pub specular: Option<Color4>,
125    pub emissive: Option<Color4>,
126    pub transparent: Option<Color4>,
127    pub reflective: Option<Color4>,
128}
129
130// Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L188
131#[derive(Debug, Clone, Default)]
132#[non_exhaustive]
133pub struct Textures {
134    pub diffuse: Option<PathBuf>,
135    pub specular: Option<PathBuf>,
136    pub ambient: Option<PathBuf>,
137    pub emissive: Option<PathBuf>,
138    pub height: Option<PathBuf>,
139    pub normal: Option<PathBuf>,
140    pub shininess: Option<PathBuf>,
141    pub opacity: Option<PathBuf>,
142    pub displacement: Option<PathBuf>,
143    pub lightmap: Option<PathBuf>,
144    pub reflection: Option<PathBuf>,
145}
146
147// Refs: https://github.com/assimp/assimp/blob/v5.3.1/include/assimp/material.h#L355
148#[derive(Debug, Clone)]
149#[non_exhaustive]
150pub enum ShadingModel {
151    Flat,
152    Gouraud,
153    Phong,
154    Blinn,
155    NoShading,
156}