1use super::builder_pool::{compute_hull_work_sizes, HullBuilder, HULL_LIMIT, SENTINEL};
4use super::types::{HullData, HullFace, HullHalfEdge, HullVertex, HULL_DATA_SIZE, HULL_VERSION};
5use super::validate::is_valid_hull;
6use crate::core::{hash, non_zero_hash, HASH_INIT};
7use crate::math_functions::{
8 add, align_up8, clamp_int, compute_cos_sin, cos, cross, length, make_matrix_from_quat,
9 make_plane_from_normal_and_point, max, min, mul, mul_mv, mul_sm, mul_sv, plane_separation,
10 safe_scale, scalar_triple_product, sin, steiner, sub, sub_mm, Transform, Vec3, PI, VEC3_ZERO,
11};
12
13fn update_hull_bounds(hull: &mut HullData) {
14 let points = &hull.points;
15 let vertex_count = hull.vertex_count as usize;
16 debug_assert!(vertex_count > 0);
17 let mut bounds = crate::math_functions::Aabb {
18 lower_bound: points[0],
19 upper_bound: points[0],
20 };
21 for i in 1..vertex_count {
22 let p = points[i];
23 bounds.lower_bound = min(bounds.lower_bound, p);
24 bounds.upper_bound = max(bounds.upper_bound, p);
25 }
26 hull.aabb = bounds;
27}
28
29fn update_hull_bulk_properties(hull: &mut HullData) -> bool {
31 let points = &hull.points;
32 let faces = &hull.faces;
33 let edges = &hull.edges;
34 let planes = &hull.planes;
35
36 let mut area = 0.0f32;
37 let mut volume = 0.0f32;
38 let mut center = VEC3_ZERO;
39 let origin = points[0];
40
41 let mut xx = 0.0f32;
42 let mut xy = 0.0f32;
43 let mut yy = 0.0f32;
44 let mut xz = 0.0f32;
45 let mut zz = 0.0f32;
46 let mut yz = 0.0f32;
47
48 let face_count = hull.face_count as usize;
49 for face_index in 0..face_count {
50 let face = faces[face_index];
51 let edge1_i = face.edge as usize;
52 let edge2_i = edges[edge1_i].next as usize;
53 let mut edge3 = edges[edge2_i].next as usize;
54
55 debug_assert!(edge1_i != edge3);
56 debug_assert!((edges[edge1_i].origin as i32) < hull.vertex_count);
57
58 let v1 = sub(points[edges[edge1_i].origin as usize], origin);
59 let mut edge2 = edge2_i;
60
61 loop {
62 debug_assert!((edges[edge2].origin as i32) < hull.vertex_count);
63 debug_assert!((edges[edge3].origin as i32) < hull.vertex_count);
64
65 let v2 = sub(points[edges[edge2].origin as usize], origin);
66 let v3 = sub(points[edges[edge3].origin as usize], origin);
67
68 area += length(cross(sub(v2, v1), sub(v3, v1)));
69
70 let det = scalar_triple_product(v1, v2, v3);
71 volume += det;
72
73 let v4 = add(v1, add(v2, v3));
74 center = add(center, mul_sv(det, v4));
75
76 xx += det * (v1.x * v1.x + v2.x * v2.x + v3.x * v3.x + v4.x * v4.x);
77 yy += det * (v1.y * v1.y + v2.y * v2.y + v3.y * v3.y + v4.y * v4.y);
78 zz += det * (v1.z * v1.z + v2.z * v2.z + v3.z * v3.z + v4.z * v4.z);
79 xy += det * (v1.x * v1.y + v2.x * v2.y + v3.x * v3.y + v4.x * v4.y);
80 xz += det * (v1.x * v1.z + v2.x * v2.z + v3.x * v3.z + v4.x * v4.z);
81 yz += det * (v1.y * v1.z + v2.y * v2.z + v3.y * v3.z + v4.y * v4.z);
82
83 edge2 = edge3;
84 edge3 = edges[edge3].next as usize;
85 if edge1_i == edge3 {
86 break;
87 }
88 }
89 }
90
91 debug_assert!(volume > 0.0);
92
93 let local_center = if volume > 0.0 {
94 mul_sv(0.25 / volume, center)
95 } else {
96 VEC3_ZERO
97 };
98 center = add(local_center, origin);
99
100 let mut radius = f32::MAX;
101 for face_index in 0..face_count {
102 let plane = planes[face_index];
103 let distance = plane_separation(plane, center);
104 debug_assert!(distance < 0.0);
105 radius = crate::math_functions::min_float(radius, -distance);
106 }
107
108 debug_assert!(0.0 < radius && radius < f32::MAX);
109
110 let mut inertia = crate::math_functions::MAT3_ZERO;
111 inertia.cx.x = yy + zz;
112 inertia.cy.x = -xy;
113 inertia.cz.x = -xz;
114 inertia.cx.y = -xy;
115 inertia.cy.y = xx + zz;
116 inertia.cz.y = -yz;
117 inertia.cx.z = -xz;
118 inertia.cy.z = -yz;
119 inertia.cz.z = xx + yy;
120
121 let mass = volume / 6.0;
122 let mut central_inertia = mul_sm(1.0 / 120.0, inertia);
123 central_inertia = sub_mm(central_inertia, steiner(mass, local_center));
124
125 hull.center = center;
126 hull.central_inertia = central_inertia;
127 hull.volume = mass;
128 hull.surface_area = 0.5 * area;
129 hull.inner_radius = radius;
130
131 mass > 0.0 && volume > 0.0 && area > 0.0 && radius > 0.0
132}
133
134fn finalize_hash(hull: &mut HullData) {
135 hull.hash = 0;
136 let bytes = hull.to_bytes_with_hash(0);
137 hull.hash = non_zero_hash(hash(HASH_INIT, &bytes));
138}
139
140pub fn create_hull(points: &[Vec3], max_vertex_count: i32) -> Option<HullData> {
142 let point_count = points.len() as i32;
143 if point_count < 4 {
144 return None;
145 }
146
147 let origin = points[0];
148 let clamped_max_count = clamp_int(max_vertex_count, 4, HULL_LIMIT);
149 let sizes = compute_hull_work_sizes(point_count, clamped_max_count);
150 let mut builder = HullBuilder::new(&sizes);
151 let mut shifted_points = vec![VEC3_ZERO; point_count as usize];
152
153 if !builder.construct(points, clamped_max_count, origin, &mut shifted_points) {
154 return None;
155 }
156
157 if builder.final_vertex_count >= HULL_LIMIT
158 || builder.final_face_count >= HULL_LIMIT
159 || builder.final_half_edge_count >= HULL_LIMIT
160 {
161 return None;
162 }
163
164 let mut temp_vertices = Vec::with_capacity(HULL_LIMIT as usize);
165 let mut vertex_count = 0i32;
166 let mut node = builder.vertex_list.next;
167 while node != SENTINEL {
168 debug_assert!(vertex_count <= HULL_LIMIT - 1);
169 builder.vertices[node as usize].final_index = vertex_count;
170 temp_vertices.push(node);
171 vertex_count += 1;
172 node = builder.vertices[node as usize].link.next;
173 }
174
175 let mut temp_faces = Vec::with_capacity(HULL_LIMIT as usize);
176 let mut temp_edges = vec![0i32; HULL_LIMIT as usize];
177 let mut face_count = 0i32;
178 let mut edge_count = 0i32;
179
180 let mut face_node = builder.face_list.next;
181 while face_node != SENTINEL {
182 debug_assert!(face_count <= HULL_LIMIT - 1);
183 let face = face_node;
184 builder.faces[face as usize].final_index = face_count;
185 temp_faces.push(face);
186 face_count += 1;
187
188 let start = builder.faces[face as usize].edge;
189 let mut edge = start;
190 loop {
191 if builder.edges[edge as usize].final_index < 0 {
192 debug_assert!(edge_count + 1 <= HULL_LIMIT - 1);
193 builder.edges[edge as usize].final_index = edge_count;
194 temp_edges[edge_count as usize] = edge;
195 edge_count += 1;
196 let twin = builder.edges[edge as usize].twin;
197 builder.edges[twin as usize].final_index = edge_count;
198 temp_edges[edge_count as usize] = twin;
199 edge_count += 1;
200 }
201 edge = builder.edges[edge as usize].next;
202 if edge == start {
203 break;
204 }
205 }
206
207 face_node = builder.faces[face as usize].link.next;
208 }
209
210 let mut byte_count = align_up8(HULL_DATA_SIZE);
211 let vertex_offset = byte_count as i32;
212 byte_count += align_up8(vertex_count as usize * core::mem::size_of::<HullVertex>());
213 let point_offset = byte_count as i32;
214 byte_count += align_up8(vertex_count as usize * core::mem::size_of::<Vec3>());
215 let edge_offset = byte_count as i32;
216 byte_count += align_up8(edge_count as usize * core::mem::size_of::<HullHalfEdge>());
217 let face_offset = byte_count as i32;
218 byte_count += align_up8(face_count as usize * core::mem::size_of::<HullFace>());
219 let plane_offset = byte_count as i32;
220 byte_count +=
221 align_up8(face_count as usize * core::mem::size_of::<crate::math_functions::Plane>());
222
223 let mut hull = HullData {
224 version: HULL_VERSION,
225 byte_count: byte_count as i32,
226 hash: 0,
227 aabb: Default::default(),
228 surface_area: 0.0,
229 volume: 0.0,
230 inner_radius: 0.0,
231 center: VEC3_ZERO,
232 central_inertia: crate::math_functions::MAT3_ZERO,
233 vertex_count,
234 vertex_offset,
235 point_offset,
236 edge_count,
237 edge_offset,
238 face_count,
239 face_offset,
240 plane_offset,
241 padding: 0,
242 vertices: vec![HullVertex { edge: 0 }; vertex_count as usize],
243 points: vec![VEC3_ZERO; vertex_count as usize],
244 edges: vec![HullHalfEdge::default(); edge_count as usize],
245 faces: vec![HullFace { edge: 0 }; face_count as usize],
246 planes: vec![
247 crate::math_functions::Plane {
248 normal: VEC3_ZERO,
249 offset: 0.0,
250 };
251 face_count as usize
252 ],
253 };
254
255 for index in 0..vertex_count as usize {
256 hull.vertices[index].edge = 0;
257 hull.points[index] = builder.vertices[temp_vertices[index] as usize].position;
258 }
259
260 for index in 0..edge_count as usize {
261 let edge = temp_edges[index];
262 let e = &builder.edges[edge as usize];
263 hull.edges[index] = HullHalfEdge {
264 next: builder.edges[e.next as usize].final_index as u8,
265 twin: builder.edges[e.twin as usize].final_index as u8,
266 face: builder.faces[e.face as usize].final_index as u8,
267 origin: builder.vertices[e.origin as usize].final_index as u8,
268 };
269 hull.vertices[builder.vertices[e.origin as usize].final_index as usize].edge = index as u8;
270 }
271
272 for index in 0..face_count as usize {
273 let face = temp_faces[index];
274 hull.faces[index].edge =
275 builder.edges[builder.faces[face as usize].edge as usize].final_index as u8;
276 hull.planes[index] = builder.faces[face as usize].plane;
277 }
278
279 update_hull_bounds(&mut hull);
280 if !update_hull_bulk_properties(&mut hull) {
281 return None;
282 }
283 if !is_valid_hull(&hull) {
284 return None;
285 }
286
287 finalize_hash(&mut hull);
288 Some(hull)
289}
290
291pub fn clone_hull(hull: &HullData) -> Option<HullData> {
293 if !is_valid_hull(hull) {
294 return None;
295 }
296 Some(hull.clone())
297}
298
299pub fn clone_and_transform_hull(
305 original: &HullData,
306 transform: Transform,
307 scale: Vec3,
308) -> Option<HullData> {
309 if !is_valid_hull(original) {
310 return None;
311 }
312
313 let mut hull = original.clone();
316
317 let safe_scale = safe_scale(scale);
318
319 let face_count = hull.face_count as usize;
320 let vertex_count = hull.vertex_count as usize;
321
322 if safe_scale.x * safe_scale.y * safe_scale.z < 0.0 {
323 for i in 0..face_count {
325 let start_edge_index = hull.faces[i].edge;
326 let mut current_edge_index = start_edge_index;
327 let mut prev_edge_index: u8 = u8::MAX;
328
329 loop {
330 let edge_next = hull.edges[current_edge_index as usize].next;
331 if edge_next == start_edge_index {
332 prev_edge_index = current_edge_index;
333 break;
334 }
335 current_edge_index = edge_next;
336 if current_edge_index == start_edge_index {
337 break;
338 }
339 }
340
341 debug_assert!(prev_edge_index != u8::MAX);
342
343 current_edge_index = start_edge_index;
344
345 loop {
346 let next_index = hull.edges[current_edge_index as usize].next;
347 let twin = hull.edges[current_edge_index as usize].twin;
348 hull.edges[current_edge_index as usize].next = prev_edge_index;
349
350 if current_edge_index < twin {
351 let a = hull.edges[current_edge_index as usize].origin;
352 let b = hull.edges[twin as usize].origin;
353 hull.edges[current_edge_index as usize].origin = b;
354 hull.edges[twin as usize].origin = a;
355 }
356
357 prev_edge_index = current_edge_index;
358 current_edge_index = next_index;
359 if current_edge_index == start_edge_index {
360 break;
361 }
362 }
363 }
364
365 for i in 0..vertex_count {
366 let edge = hull.vertices[i].edge;
367 hull.vertices[i].edge = hull.edges[edge as usize].twin;
368 }
369 }
370
371 let matrix = make_matrix_from_quat(transform.q);
372 for i in 0..vertex_count {
373 hull.points[i] = add(mul_mv(matrix, mul(safe_scale, hull.points[i])), transform.p);
374 }
375
376 for i in 0..face_count {
377 let mut count = 0i32;
378 let mut centroid = VEC3_ZERO;
379 let mut normal = VEC3_ZERO;
380
381 let start_edge_index = hull.faces[i].edge;
382 let mut current_edge_index = start_edge_index;
383
384 debug_assert!(hull.edges[start_edge_index as usize].face as usize == i);
385 debug_assert!((hull.edges[start_edge_index as usize].origin as i32) < hull.vertex_count);
386
387 let origin = hull.points[hull.edges[start_edge_index as usize].origin as usize];
388
389 loop {
390 let edge = hull.edges[current_edge_index as usize];
391 let twin = hull.edges[edge.twin as usize];
392 debug_assert!(twin.twin == current_edge_index);
393
394 let v1 = sub(hull.points[edge.origin as usize], origin);
395 let v2 = sub(hull.points[twin.origin as usize], origin);
396
397 count += 1;
398 centroid = add(centroid, v1);
399 normal.x += (v1.y - v2.y) * (v1.z + v2.z);
400 normal.y += (v1.z - v2.z) * (v1.x + v2.x);
401 normal.z += (v1.x - v2.x) * (v1.y + v2.y);
402
403 current_edge_index = edge.next;
404 if current_edge_index == start_edge_index {
405 break;
406 }
407 }
408
409 debug_assert!(count > 0);
410 centroid = mul_sv(1.0 / count as f32, centroid);
411 centroid = add(centroid, origin);
412
413 let area = length(normal);
414 debug_assert!(area > 0.0);
415 normal = mul_sv(1.0 / area, normal);
416
417 hull.planes[i] = make_plane_from_normal_and_point(normal, centroid);
418 }
419
420 update_hull_bounds(&mut hull);
421 if !update_hull_bulk_properties(&mut hull) {
422 return None;
423 }
424
425 finalize_hash(&mut hull);
426
427 debug_assert!(is_valid_hull(&hull));
428
429 Some(hull)
430}
431
432pub fn destroy_hull(_hull: HullData) {}
434
435pub fn create_cylinder(height: f32, radius: f32, y_offset: f32, sides: i32) -> Option<HullData> {
437 debug_assert!(height > 0.0);
438 debug_assert!(radius > 0.0);
439 debug_assert!((3..=32).contains(&sides));
440
441 let point_count = 2 * sides;
442 let mut points = Vec::with_capacity(point_count as usize);
443 let mut alpha = 0.0f32;
444 let delta_alpha = 2.0 * PI / sides as f32;
445
446 for _ in 0..sides {
447 let sin_alpha = sin(alpha);
448 let cos_alpha = cos(alpha);
449 points.push(Vec3 {
450 x: radius * cos_alpha,
451 y: y_offset,
452 z: radius * sin_alpha,
453 });
454 points.push(Vec3 {
455 x: radius * cos_alpha,
456 y: y_offset + height,
457 z: radius * sin_alpha,
458 });
459 alpha += delta_alpha;
460 }
461
462 let hull = create_hull(&points, point_count)?;
463 debug_assert!(hull.vertex_count == point_count);
464 debug_assert!(hull.edge_count == 6 * sides);
465 debug_assert!(hull.face_count == sides + 2);
466 Some(hull)
467}
468
469pub fn create_cone(height: f32, radius1: f32, radius2: f32, slices: i32) -> Option<HullData> {
471 debug_assert!(height > 0.0);
472 debug_assert!(radius1 > 0.0);
473 debug_assert!(radius2 > 0.0);
474 debug_assert!((4..=32).contains(&slices));
475
476 let point_count = 2 * slices;
477 let mut points = Vec::with_capacity(point_count as usize);
478 let mut alpha = 0.0f32;
479 let delta_alpha = 2.0 * PI / slices as f32;
480
481 for _ in 0..slices {
482 let sin_alpha = sin(alpha);
483 let cos_alpha = cos(alpha);
484 points.push(Vec3 {
485 x: radius1 * cos_alpha,
486 y: 0.0,
487 z: radius1 * sin_alpha,
488 });
489 points.push(Vec3 {
490 x: radius2 * cos_alpha,
491 y: height,
492 z: radius2 * sin_alpha,
493 });
494 alpha += delta_alpha;
495 }
496
497 let hull = create_hull(&points, point_count)?;
498 debug_assert!(hull.vertex_count == point_count);
499 debug_assert!(hull.edge_count == 6 * slices);
500 debug_assert!(hull.face_count == slices + 2);
501 Some(hull)
502}
503
504pub fn create_rock(radius: f32) -> Option<HullData> {
506 let point_count = 10;
507 let phi = (1.0 + 5.0f32.sqrt()) / 2.0;
508 let theta = 2.0 * PI / phi;
509 let mut cs = crate::math_functions::CosSin {
510 cosine: 1.0,
511 sine: 0.0,
512 };
513 let delta_cs = compute_cos_sin(theta);
514 let mut points = [VEC3_ZERO; 10];
515
516 for i in 0..point_count {
517 let z = 1.0 - (2.0 * i as f32 + 1.0) / point_count as f32;
518 let radius_xy = (1.0 - z * z).sqrt();
519 points[i] = Vec3 {
520 x: radius * radius_xy * cs.cosine,
521 y: radius * radius_xy * cs.sine,
522 z: radius * z,
523 };
524 let cs0 = cs;
525 cs.cosine = delta_cs.cosine * cs0.cosine - delta_cs.sine * cs0.sine;
526 cs.sine = delta_cs.sine * cs0.cosine + delta_cs.cosine * cs0.sine;
527 }
528
529 create_hull(&points, point_count as i32)
530}