crystal_api/
mesh.rs

1use std::{
2    io::{BufRead, BufReader},
3    mem::offset_of,
4};
5
6use crate::errors::GraphicsResult;
7
8/// Used to setup vertex shader attributes
9pub struct Attribute {
10    pub(crate) size: usize,
11    pub(crate) offset: usize,
12}
13
14type Vec3 = [f32; 3];
15type Vec2 = [f32; 2];
16
17/// Index type
18pub type Index = u32;
19
20/// Textured vertex struct
21#[repr(C, align(16))]
22#[derive(Clone, Copy, Default)]
23pub struct VertexTexture {
24    pos: Vec3,
25    nor: Vec3,
26    uv: Vec2,
27    col: Vec3,
28}
29
30impl VertexTexture {
31    /// Gets list of vertex attributes used in shaders
32    pub fn get_attributes() -> Vec<Attribute> {
33        vec![
34            Attribute {
35                size: size_of::<Vec3>(),
36                offset: offset_of!(Self, pos),
37            },
38            Attribute {
39                size: size_of::<Vec3>(),
40                offset: offset_of!(Self, nor),
41            },
42            Attribute {
43                size: size_of::<Vec2>(),
44                offset: offset_of!(Self, uv),
45            },
46            Attribute {
47                size: size_of::<Vec3>(),
48                offset: offset_of!(Self, col),
49            },
50        ]
51    }
52}
53
54/// Mesh struct stores the mesh data in CPU memory
55pub struct Mesh {
56    pub(crate) vertices: Vec<VertexTexture>,
57    pub(crate) indices: Vec<Index>,
58}
59
60impl Mesh {
61    /// Creates screen space plane mesh may be used for post-processing
62    pub fn screen_space_plane() -> Self {
63        let vertices = vec![
64            VertexTexture {
65                pos: [0., 0., 0.],
66                ..Default::default()
67            },
68            VertexTexture {
69                pos: [1., 0., 0.],
70                ..Default::default()
71            },
72            VertexTexture {
73                pos: [1., -1., 0.],
74                ..Default::default()
75            },
76            VertexTexture {
77                pos: [-1., -1., 0.],
78                ..Default::default()
79            },
80        ];
81
82        Self {
83            vertices,
84            indices: vec![0, 1, 2, 2, 3, 0],
85        }
86    }
87
88    /// Creates the mesh from buffer with ```.obj``` format
89    pub fn from_buffer<T>(buffer: BufReader<T>) -> GraphicsResult<Self>
90    where
91        BufReader<T>: BufRead,
92    {
93        let mut vertices = vec![];
94        let mut indices = vec![];
95        let mut normals: Vec<[f32; 3]> = vec![];
96        let mut uvs: Vec<[f32; 2]> = vec![];
97
98        for line in buffer.lines() {
99            let line = match line {
100                Ok(line) => line,
101                Err(_) => continue,
102            };
103
104            let splitted: Vec<&str> = line.split_whitespace().collect();
105
106            if splitted.len() == 0 || splitted[0].chars().next().unwrap() == '#' {
107                continue;
108            }
109
110            if splitted.len() >= 3 {
111                match splitted[0] {
112                    "vn" => normals.push([
113                        splitted[1].parse().unwrap(),
114                        splitted[2].parse().unwrap(),
115                        splitted[3].parse().unwrap(),
116                    ]),
117                    "vt" => uvs.push([splitted[1].parse().unwrap(), splitted[2].parse().unwrap()]),
118                    "v" => vertices.push(VertexTexture {
119                        pos: [
120                            splitted[1].parse().unwrap(),
121                            splitted[2].parse().unwrap(),
122                            splitted[3].parse().unwrap(),
123                        ],
124                        nor: [0., 0., 0.],
125                        uv: [0., 0.],
126                        col: if splitted.len() != 7 {
127                            [0., 0., 0.]
128                        } else {
129                            [
130                                splitted[4].parse().unwrap_or(0.),
131                                splitted[5].parse().unwrap_or(0.),
132                                splitted[6].parse().unwrap_or(0.),
133                            ]
134                        },
135                    }),
136                    "f" => {
137                        let mut local_indices = vec![];
138
139                        for &data in &splitted[1..] {
140                            if data.chars().next().unwrap() == '#' {
141                                break;
142                            }
143                            let splitted: Vec<&str> = data.split('/').collect();
144
145                            let idx: i32 = splitted[0].parse().unwrap();
146                            let idx: Index = if idx >= 0 {
147                                (idx - 1) as Index
148                            } else {
149                                (idx + vertices.len() as i32) as Index
150                            };
151
152                            if splitted[1].len() > 0 {
153                                let uv: i32 = splitted[1].parse().unwrap();
154                                let uv: usize = if uv >= 0 {
155                                    (uv - 1) as usize
156                                } else {
157                                    (uv + uvs.len() as i32) as usize
158                                };
159                                vertices[idx as usize].uv = uvs[uv];
160                            }
161
162                            if splitted.len() > 2 && splitted[2].len() > 0 {
163                                let nor: i32 = splitted[2].parse().unwrap();
164                                let nor: usize = if nor >= 0 {
165                                    (nor - 1) as usize
166                                } else {
167                                    (nor + normals.len() as i32) as usize
168                                };
169                                vertices[idx as usize].nor = normals[nor];
170                            }
171
172                            local_indices.push(idx);
173                        }
174
175                        if local_indices.len() == 3 {
176                            indices.append(&mut local_indices);
177                        } else if local_indices.len() == 4 {
178                            indices.push(local_indices[0]);
179                            indices.push(local_indices[1]);
180                            indices.push(local_indices[2]);
181
182                            indices.push(local_indices[0]);
183                            indices.push(local_indices[2]);
184                            indices.push(local_indices[3]);
185                        }
186                    }
187
188                    _ => (),
189                }
190            }
191        }
192
193        Ok(Self { vertices, indices })
194    }
195}