1use crate::aabb::Aabb;
2
3#[repr(C)]
5#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
6pub struct MeshVertex {
7 pub position: [f32; 3],
8 pub normal: [f32; 3],
9 pub uv: [f32; 2],
10 pub tangent: [f32; 4],
11}
12
13impl MeshVertex {
14 pub const SIZE: usize = std::mem::size_of::<Self>();
15 pub const ATTRIB_COUNT: usize = 4;
16}
17
18#[derive(Debug, Clone)]
20pub struct SubMesh {
21 pub material_index: usize,
22 pub index_offset: u32,
23 pub index_count: u32,
24}
25
26#[derive(Debug, Clone)]
28pub struct Mesh {
29 pub name: String,
30 pub vertices: Vec<MeshVertex>,
31 pub indices: Vec<u32>,
32 pub sub_meshes: Vec<SubMesh>,
33 pub aabb: Aabb,
34}
35
36impl Mesh {
37 pub fn extract_edge_indices(&self) -> Vec<u32> {
40 let mut edge_indices = Vec::with_capacity(self.indices.len() * 2);
41 for tri in self.indices.chunks(3) {
42 if tri.len() == 3 {
43 edge_indices.extend_from_slice(&[tri[0], tri[1], tri[1], tri[2], tri[2], tri[0]]);
44 }
45 }
46 edge_indices
47 }
48
49 pub fn from_triangles(
53 name: impl Into<String>,
54 positions: &[[f32; 3]],
55 indices: &[u32],
56 ) -> Self {
57 let n_verts = positions.len();
58 let mut smooth_normals = vec![[0.0_f32; 3]; n_verts];
59
60 for tri in indices.chunks_exact(3) {
61 let i0 = tri[0] as usize;
62 let i1 = tri[1] as usize;
63 let i2 = tri[2] as usize;
64 let p0 = glam::Vec3::from(positions[i0]);
65 let p1 = glam::Vec3::from(positions[i1]);
66 let p2 = glam::Vec3::from(positions[i2]);
67 let n = (p1 - p0).cross(p2 - p0);
68 for &i in &[i0, i1, i2] {
69 smooth_normals[i][0] += n.x;
70 smooth_normals[i][1] += n.y;
71 smooth_normals[i][2] += n.z;
72 }
73 }
74 for n in &mut smooth_normals {
75 let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
76 if len > 1e-10 {
77 let inv = 1.0 / len;
78 n[0] *= inv; n[1] *= inv; n[2] *= inv;
79 } else { *n = [0.0, 1.0, 0.0]; }
80 }
81
82 let vertices: Vec<MeshVertex> = positions.iter().zip(smooth_normals.iter())
83 .map(|(pos, norm)| MeshVertex {
84 position: *pos, normal: *norm,
85 uv: [0.0, 0.0], tangent: [1.0, 0.0, 0.0, 1.0],
86 }).collect();
87
88 let mut aabb = crate::Aabb::empty();
89 for p in positions { aabb.expand(glam::Vec3::from(*p)); }
90
91 let index_count = indices.len() as u32;
92 Mesh {
93 name: name.into(),
94 vertices,
95 indices: indices.to_vec(),
96 sub_meshes: vec![SubMesh { material_index: 0, index_offset: 0, index_count }],
97 aabb,
98 }
99 }
100}
101
102pub fn create_cube_mesh() -> Mesh {
104 let mut vertices = Vec::new();
105 let mut indices = Vec::new();
106 let mut aabb = Aabb::empty();
107
108 let faces: [([f32; 3], [f32; 3], [f32; 4]); 6] = [
110 ([0.0, 1.0, 0.0], [0.0, 1.0, 0.0], [1.0, 0.0, 0.0, 1.0]),
112 ([0.0, -1.0, 0.0], [0.0, -1.0, 0.0], [-1.0, 0.0, 0.0, 1.0]),
114 ([1.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 0.0, -1.0, 1.0]),
116 ([-1.0, 0.0, 0.0], [-1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 1.0]),
118 ([0.0, 0.0, 1.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0, 1.0]),
120 ([0.0, 0.0, -1.0], [0.0, 0.0, -1.0], [-1.0, 0.0, 0.0, 1.0]),
122 ];
123
124 let face_vertices: [[([f32; 3], [f32; 2]); 4]; 6] = [
125 [
127 ([-0.5, 0.5, -0.5], [0.0, 0.0]),
128 ([0.5, 0.5, -0.5], [1.0, 0.0]),
129 ([0.5, 0.5, 0.5], [1.0, 1.0]),
130 ([-0.5, 0.5, 0.5], [0.0, 1.0]),
131 ],
132 [
134 ([-0.5, -0.5, 0.5], [0.0, 0.0]),
135 ([0.5, -0.5, 0.5], [1.0, 0.0]),
136 ([0.5, -0.5, -0.5], [1.0, 1.0]),
137 ([-0.5, -0.5, -0.5], [0.0, 1.0]),
138 ],
139 [
141 ([0.5, -0.5, -0.5], [0.0, 0.0]),
142 ([0.5, -0.5, 0.5], [1.0, 0.0]),
143 ([0.5, 0.5, 0.5], [1.0, 1.0]),
144 ([0.5, 0.5, -0.5], [0.0, 1.0]),
145 ],
146 [
148 ([-0.5, -0.5, 0.5], [0.0, 0.0]),
149 ([-0.5, -0.5, -0.5], [1.0, 0.0]),
150 ([-0.5, 0.5, -0.5], [1.0, 1.0]),
151 ([-0.5, 0.5, 0.5], [0.0, 1.0]),
152 ],
153 [
155 ([0.5, -0.5, 0.5], [0.0, 0.0]),
156 ([-0.5, -0.5, 0.5], [1.0, 0.0]),
157 ([-0.5, 0.5, 0.5], [1.0, 1.0]),
158 ([0.5, 0.5, 0.5], [0.0, 1.0]),
159 ],
160 [
162 ([-0.5, -0.5, -0.5], [0.0, 0.0]),
163 ([0.5, -0.5, -0.5], [1.0, 0.0]),
164 ([0.5, 0.5, -0.5], [1.0, 1.0]),
165 ([-0.5, 0.5, -0.5], [0.0, 1.0]),
166 ],
167 ];
168
169 for (face_idx, (normal, _, tangent)) in faces.iter().enumerate() {
170 let base = vertices.len() as u32;
171 for (pos, uv) in &face_vertices[face_idx] {
172 vertices.push(MeshVertex {
173 position: *pos,
174 normal: *normal,
175 uv: *uv,
176 tangent: *tangent,
177 });
178 aabb.expand(glam::Vec3::from(*pos));
179 }
180 indices.extend_from_slice(&[
181 base, base + 2, base + 1,
182 base, base + 3, base + 2,
183 ]);
184 }
185
186 let index_count = indices.len() as u32;
187 Mesh {
188 name: "Cube".to_string(),
189 vertices,
190 indices,
191 sub_meshes: vec![SubMesh {
192 material_index: 0,
193 index_offset: 0,
194 index_count,
195 }],
196 aabb,
197 }
198}