1use super::bvh::{
7 build_recursive, collect_primitives, fill_triangles, sort_mesh_triangles, weld_vertices,
8};
9use super::types::{
10 MeshData, MeshDef, MeshNode, MeshTriangle, CONCAVE_EDGE1, CONCAVE_EDGE2, CONCAVE_EDGE3,
11 INVERSE_CONCAVE_EDGE1, INVERSE_CONCAVE_EDGE2, INVERSE_CONCAVE_EDGE3, MESH_DATA_SIZE,
12 MESH_NODE_SIZE, MESH_TRIANGLE_SIZE, MESH_VERSION,
13};
14use crate::core::{hash, non_zero_hash, HASH_INIT, NULL_INDEX};
15use crate::math_functions::{
16 align_up8, cross, dot, max_int, min_int, normalize, signed_volume, sub, Vec3,
17};
18use std::collections::HashMap;
19
20struct MeshEdge {
21 vertex1: i32,
22 vertex2: i32,
23 triangle1: i32,
24 triangle2: i32,
25 triangle_count: u16,
26 triangle_edge_index1: u8,
27 triangle_edge_index2: u8,
28}
29
30fn identify_edges(mesh: &mut MeshData) {
31 let triangle_count = mesh.triangle_count as usize;
32 let edge_count = 3 * triangle_count;
33 let mut edges = Vec::with_capacity(edge_count);
34 let mut normals = vec![Vec3::default(); triangle_count];
35
36 for i in 0..triangle_count {
37 let triangle = mesh.triangles[i];
38 let i1 = triangle.index1;
39 let i2 = triangle.index2;
40 let i3 = triangle.index3;
41
42 edges.push(MeshEdge {
43 vertex1: min_int(i1, i2),
44 vertex2: max_int(i1, i2),
45 triangle1: i as i32,
46 triangle2: NULL_INDEX,
47 triangle_edge_index1: 0,
48 triangle_edge_index2: 0xFF,
49 triangle_count: 1,
50 });
51 edges.push(MeshEdge {
52 vertex1: min_int(i2, i3),
53 vertex2: max_int(i2, i3),
54 triangle1: i as i32,
55 triangle2: NULL_INDEX,
56 triangle_edge_index1: 1,
57 triangle_edge_index2: 0xFF,
58 triangle_count: 1,
59 });
60 edges.push(MeshEdge {
61 vertex1: min_int(i3, i1),
62 vertex2: max_int(i3, i1),
63 triangle1: i as i32,
64 triangle2: NULL_INDEX,
65 triangle_edge_index1: 2,
66 triangle_edge_index2: 0xFF,
67 triangle_count: 1,
68 });
69
70 let v1 = mesh.vertices[i1 as usize];
71 let v2 = mesh.vertices[i2 as usize];
72 let v3 = mesh.vertices[i3 as usize];
73 let e1 = sub(v2, v1);
74 let e2 = sub(v3, v1);
75 let n = cross(e1, e2);
76 normals[i] = normalize(n);
77 }
78
79 let mut map: HashMap<u64, i32> = HashMap::with_capacity(edge_count);
80 let key0 = ((edges[0].vertex1 as u64) << 32) | (edges[0].vertex2 as u64);
81 map.insert(key0, 0);
82
83 for i in 1..edge_count {
84 let key = ((edges[i].vertex1 as u64) << 32) | (edges[i].vertex2 as u64);
85 let triangle1 = edges[i].triangle1;
86 let triangle_edge_index1 = edges[i].triangle_edge_index1;
87 if let Some(&other_index) = map.get(&key) {
88 debug_assert!((other_index as usize) < i);
89 let base = &mut edges[other_index as usize];
90 if base.triangle_count == 1 {
91 base.triangle2 = triangle1;
92 base.triangle_edge_index2 = triangle_edge_index1;
93 }
94 base.triangle_count += 1;
95 } else {
96 map.insert(key, i as i32);
97 }
98 }
99 drop(map);
100
101 let edge_flags_concave = [CONCAVE_EDGE1, CONCAVE_EDGE2, CONCAVE_EDGE3];
102 let edge_flags_inverse = [
103 INVERSE_CONCAVE_EDGE1,
104 INVERSE_CONCAVE_EDGE2,
105 INVERSE_CONCAVE_EDGE3,
106 ];
107
108 for i in 0..edge_count {
109 let edge = &edges[i];
110 if edge.triangle_count != 2 {
111 continue;
112 }
113
114 debug_assert!(edge.triangle_edge_index1 < 3);
115 debug_assert!(edge.triangle_edge_index2 < 3);
116
117 let triangle1 = mesh.triangles[edge.triangle1 as usize];
118 let triangle2 = mesh.triangles[edge.triangle2 as usize];
119
120 let j1 = triangle2.index1;
121 let j2 = triangle2.index2;
122 let j3 = triangle2.index3;
123
124 let opposite = match edge.triangle_edge_index2 {
125 0 => j3,
126 1 => j1,
127 2 => j2,
128 _ => unreachable!(),
129 };
130
131 let i1 = triangle1.index1;
132 let i2 = triangle1.index2;
133 let i3 = triangle1.index3;
134
135 let v1 = mesh.vertices[i1 as usize];
136 let v2 = mesh.vertices[i2 as usize];
137 let v3 = mesh.vertices[i3 as usize];
138 let p = mesh.vertices[opposite as usize];
139
140 let cos5_deg = 0.9962f32;
141 let signed_vol = signed_volume(v1, v2, v3, p);
142 let n1 = normals[edge.triangle1 as usize];
143 let n2 = normals[edge.triangle2 as usize];
144 let cos_angle = dot(n1, n2);
145
146 if signed_vol > 0.0 || cos_angle > cos5_deg {
147 mesh.flags[edge.triangle1 as usize] |=
148 edge_flags_concave[edge.triangle_edge_index1 as usize] as u8;
149 mesh.flags[edge.triangle2 as usize] |=
150 edge_flags_concave[edge.triangle_edge_index2 as usize] as u8;
151 }
152
153 if signed_vol < 0.0 || cos_angle > cos5_deg {
154 mesh.flags[edge.triangle1 as usize] |=
155 edge_flags_inverse[edge.triangle_edge_index1 as usize] as u8;
156 mesh.flags[edge.triangle2 as usize] |=
157 edge_flags_inverse[edge.triangle_edge_index2 as usize] as u8;
158 }
159 }
160}
161
162fn node_height(nodes: &[MeshNode], index: usize) -> i32 {
163 let node = &nodes[index];
164 if node.is_leaf() {
165 return 0;
166 }
167 let left = node_height(nodes, index + 1);
168 let right = node_height(nodes, index + node.child_offset() as usize);
169 1 + left.max(right)
170}
171
172pub fn get_height(mesh: &MeshData) -> i32 {
174 if mesh.nodes.is_empty() {
175 return 0;
176 }
177 node_height(&mesh.nodes, 0)
178}
179
180pub fn is_valid_mesh(mesh: Option<&MeshData>) -> bool {
182 let Some(mesh) = mesh else {
183 return false;
184 };
185 if mesh.version != MESH_VERSION {
186 return false;
187 }
188 if mesh.byte_count < MESH_DATA_SIZE as i32 {
189 return false;
190 }
191 true
192}
193
194pub fn create_mesh(
199 def: &MeshDef,
200 degenerate_triangle_indices: Option<&mut [i32]>,
201) -> Option<MeshData> {
202 let vertex_count_in = def.vertices.len() as i32;
203 let triangle_count_in = (def.indices.len() / 3) as i32;
204
205 if vertex_count_in < 3 || triangle_count_in <= 0 || def.indices.len() < 3 {
206 return None;
207 }
208
209 let mut indices = vec![0i32; (3 * triangle_count_in) as usize];
210 let mut vertices: Vec<Vec3>;
211 let mut vertex_count = vertex_count_in;
212
213 if def.weld_vertices && def.weld_tolerance > 0.0 {
214 vertices = vec![Vec3::default(); vertex_count as usize];
215 vertex_count = weld_vertices(
216 &def.vertices,
217 &def.indices[..(3 * triangle_count_in) as usize],
218 &mut vertices,
219 &mut indices,
220 def.weld_tolerance,
221 );
222 vertices.truncate(vertex_count as usize);
223 debug_assert!(vertex_count <= vertex_count_in);
224 } else {
225 vertices = def.vertices.clone();
226 indices.copy_from_slice(&def.indices[..(3 * triangle_count_in) as usize]);
227 }
228
229 let src_materials = if def.material_indices.is_empty() {
230 None
231 } else {
232 Some(def.material_indices.as_slice())
233 };
234
235 let (mut primitives, degenerate_count, surface_area, material_count, mesh_bounds) =
236 collect_primitives(&vertices, &indices, src_materials, triangle_count_in);
237
238 if let Some(out) = degenerate_triangle_indices {
239 let min_area = 0.01 * crate::constants::linear_slop() * crate::constants::linear_slop();
240 let mut written = 0usize;
241 let mut seen = 0i32;
242 for index in 0..triangle_count_in {
243 let index1 = indices[(3 * index) as usize];
244 let index2 = indices[(3 * index + 1) as usize];
245 let index3 = indices[(3 * index + 2) as usize];
246 let vertex1 = vertices[index1 as usize];
247 let vertex2 = vertices[index2 as usize];
248 let vertex3 = vertices[index3 as usize];
249 let normal = cross(sub(vertex2, vertex1), sub(vertex3, vertex1));
250 let area = 0.5 * crate::math_functions::length(normal);
251 if area < min_area && index1 != index2 && index1 != index3 && index2 != index3 {
252 seen += 1;
253 if written < out.len() {
254 out[written] = index;
255 written += 1;
256 }
257 }
258 }
259 debug_assert_eq!(seen, degenerate_count);
260 let _ = seen;
261 }
262
263 let triangle_count = primitives.len() as i32;
264 if !crate::math_functions::is_sane_aabb(mesh_bounds) {
265 return None;
266 }
267
268 let mut temp_nodes = Vec::with_capacity((2 * triangle_count - 1).max(1) as usize);
269 let mut tree_height = 0i32;
270 build_recursive(
271 &mut temp_nodes,
272 triangle_count,
273 &mut primitives,
274 0,
275 def.use_median_split,
276 &mut tree_height,
277 );
278
279 let mut byte_count = align_up8(MESH_DATA_SIZE);
280 let node_offset = byte_count as i32;
281 byte_count += align_up8(temp_nodes.len() * MESH_NODE_SIZE);
282 let vertex_offset = byte_count as i32;
283 byte_count += align_up8(vertex_count as usize * core::mem::size_of::<Vec3>());
284 let triangle_offset = byte_count as i32;
285 byte_count += align_up8(triangle_count as usize * MESH_TRIANGLE_SIZE);
286 let material_indices_offset = byte_count as i32;
287 byte_count += align_up8(triangle_count as usize);
288 let flags_offset = byte_count as i32;
289 byte_count += align_up8(triangle_count as usize);
290
291 let mut mesh = MeshData {
292 version: MESH_VERSION,
293 byte_count: byte_count as i32,
294 hash: 0,
295 bounds: mesh_bounds,
296 surface_area,
297 node_count: temp_nodes.len() as i32,
298 tree_height,
299 vertex_count,
300 triangle_count,
301 degenerate_count,
302 node_offset,
303 vertex_offset,
304 triangle_offset,
305 material_offset: material_indices_offset,
306 material_count,
307 flags_offset,
308 nodes: temp_nodes,
309 vertices,
310 triangles: vec![MeshTriangle::default(); triangle_count as usize],
311 material_indices: vec![0u8; triangle_count as usize],
312 flags: vec![0u8; triangle_count as usize],
313 };
314
315 fill_triangles(
316 &mut mesh.triangles,
317 &mut mesh.material_indices,
318 &mut mesh.flags,
319 &primitives,
320 &indices,
321 src_materials,
322 );
323
324 if !sort_mesh_triangles(&mut mesh) {
325 return None;
326 }
327
328 if def.identify_edges {
329 identify_edges(&mut mesh);
330 }
331
332 let bytes = mesh.to_bytes_with_hash(0);
333 mesh.hash = non_zero_hash(hash(HASH_INIT, &bytes));
334
335 Some(mesh)
336}
337
338pub fn destroy_mesh(_mesh: MeshData) {}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344 use crate::math_functions::Vec3;
345
346 #[test]
349 fn create_mesh_collects_degenerate_triangle_indices() {
350 let def = MeshDef {
352 vertices: vec![
353 Vec3 {
354 x: 0.0,
355 y: 0.0,
356 z: 0.0,
357 },
358 Vec3 {
359 x: 1.0,
360 y: 0.0,
361 z: 0.0,
362 },
363 Vec3 {
364 x: 0.0,
365 y: 1.0,
366 z: 0.0,
367 },
368 Vec3 {
369 x: 2.0,
370 y: 0.0,
371 z: 0.0,
372 }, ],
374 indices: vec![0, 1, 2, 0, 1, 3],
375 material_indices: vec![],
376 weld_tolerance: 0.0,
377 weld_vertices: false,
378 use_median_split: true,
379 identify_edges: false,
380 };
381 let mut degenerate = [-1i32; 8];
382 let mesh = create_mesh(&def, Some(&mut degenerate)).expect("mesh");
383 assert_eq!(mesh.degenerate_count, 1);
384 assert_eq!(mesh.triangle_count, 1); assert_eq!(degenerate[0], 1); assert_eq!(degenerate[1], -1); }
388
389 #[test]
393 fn create_mesh_viewer_flags_weld_and_identify_edges() {
394 let def = MeshDef {
395 vertices: vec![
396 Vec3 {
397 x: 0.0,
398 y: 0.0,
399 z: 0.0,
400 },
401 Vec3 {
402 x: 1.0,
403 y: 0.0,
404 z: 0.0,
405 },
406 Vec3 {
407 x: 0.0,
408 y: 1.0,
409 z: 0.0,
410 },
411 Vec3 {
412 x: 0.0005,
413 y: 0.0,
414 z: 0.0,
415 }, ],
417 indices: vec![0, 1, 2, 3, 1, 2],
418 material_indices: vec![0, 1],
419 weld_tolerance: 0.0015,
420 weld_vertices: true,
421 use_median_split: true,
422 identify_edges: true,
423 };
424 let mut degenerate = [0i32; 8];
425 let mesh = create_mesh(&def, Some(&mut degenerate)).expect("mesh");
426 assert!(mesh.triangle_count >= 1);
427 assert!(mesh.vertex_count <= 3); assert!(mesh.degenerate_count >= 0);
429 }
430}