1use fast_mesh_store::{Transaction, UV_CHANNEL, VertexId};
39
40use crate::{OpsError, Result, push, reserve};
41
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
44pub enum SubdivideMethod {
45 #[default]
48 Loop,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub struct SubdivideOptions {
54 pub method: SubdivideMethod,
56 pub levels: u32,
59}
60
61impl Default for SubdivideOptions {
62 fn default() -> Self {
63 SubdivideOptions {
64 method: SubdivideMethod::Loop,
65 levels: 1,
66 }
67 }
68}
69
70impl SubdivideOptions {
71 pub fn builder() -> SubdivideOptionsBuilder {
73 SubdivideOptionsBuilder::default()
74 }
75}
76
77#[derive(Debug, Clone, Default)]
79pub struct SubdivideOptionsBuilder {
80 options: SubdivideOptions,
81}
82
83impl SubdivideOptionsBuilder {
84 pub fn method(mut self, method: SubdivideMethod) -> Self {
86 self.options.method = method;
87 self
88 }
89
90 pub fn levels(mut self, levels: u32) -> Self {
92 self.options.levels = levels;
93 self
94 }
95
96 pub fn build(self) -> SubdivideOptions {
98 self.options
99 }
100}
101
102#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
104pub struct SubdivideReport {
105 pub vertices_added: usize,
107 pub triangles_added: usize,
109}
110
111struct WorkTri {
115 slot: Option<u32>,
116 corners: [u32; 3],
117 clean: bool,
118}
119
120fn f64v(p: &[f32; 3]) -> [f64; 3] {
121 [f64::from(p[0]), f64::from(p[1]), f64::from(p[2])]
122}
123
124fn key(a: u32, b: u32) -> (u32, u32) {
126 if a < b { (a, b) } else { (b, a) }
127}
128
129fn loop_beta(n: usize) -> f64 {
131 use std::f64::consts::PI;
132 let n = n as f64;
133 (5.0 / 8.0 - (3.0 / 8.0 + 0.25 * (2.0 * PI / n).cos()).powi(2)) / n
134}
135
136fn step(
140 pos: &mut Vec<[f32; 3]>,
141 vlive: &mut Vec<bool>,
142 tris: &mut Vec<WorkTri>,
143 uvs: Option<&mut Vec<f32>>,
144) -> Result<bool> {
145 let clean = tris.iter().filter(|t| t.clean).count();
146 if clean == 0 {
147 return Ok(false);
148 }
149 let slots = pos.len();
150
151 let mut entries: Vec<((u32, u32), u32, u32)> = Vec::new();
154 reserve(
155 &mut entries,
156 clean.checked_mul(3).ok_or(crate::OpsError::Store(
157 fast_mesh_store::StoreError::OutOfMemory,
158 ))?,
159 )?;
160 for (i, tri) in tris.iter().enumerate() {
161 if !tri.clean {
162 continue;
163 }
164 let [a, b, c] = tri.corners;
165 push(&mut entries, (key(a, b), i as u32, c))?;
166 push(&mut entries, (key(b, c), i as u32, a))?;
167 push(&mut entries, (key(c, a), i as u32, b))?;
168 }
169 entries.sort_unstable();
170
171 let mut edges: Vec<(u32, u32)> = Vec::new();
173 reserve(&mut edges, entries.len())?;
174 let mut owners: Vec<usize> = Vec::new();
175 reserve(&mut owners, entries.len())?;
176 let mut apexes: Vec<[u32; 2]> = Vec::new();
177 reserve(&mut apexes, entries.len())?;
178 {
179 let mut start = 0;
180 while start < entries.len() {
181 let mut end = start + 1;
182 while end < entries.len() && entries[end].0 == entries[start].0 {
183 end += 1;
184 }
185 let (a, b) = entries[start].0;
186 push(&mut edges, (a, b))?;
187 push(&mut owners, end - start)?;
188 let mut pair = [entries[start].2, entries[start].2];
189 if end - start == 2 {
190 pair[1] = entries[start + 1].2;
191 }
192 push(&mut apexes, pair)?;
193 start = end;
194 }
195 }
196
197 let mut nbs: Vec<Vec<u32>> = Vec::new();
200 reserve(&mut nbs, slots)?;
201 nbs.resize_with(slots, Vec::new);
202 let mut bnd: Vec<Vec<u32>> = Vec::new();
203 reserve(&mut bnd, slots)?;
204 bnd.resize_with(slots, Vec::new);
205 for tri in tris.iter() {
206 if !tri.clean {
207 continue;
208 }
209 let [a, b, c] = tri.corners;
210 for (v, w) in [(a, b), (a, c), (b, a), (b, c), (c, a), (c, b)] {
211 push(&mut nbs[v as usize], w)?;
212 }
213 }
214 for (k, &(a, b)) in edges.iter().enumerate() {
215 if owners[k] == 1 {
216 push(&mut bnd[a as usize], b)?;
217 push(&mut bnd[b as usize], a)?;
218 }
219 }
220 for v in 0..slots {
221 if vlive[v] {
222 nbs[v].sort_unstable();
223 nbs[v].dedup();
224 bnd[v].sort_unstable();
225 bnd[v].dedup();
226 }
227 }
228
229 let mut upd: Vec<[f32; 3]> = Vec::new();
231 reserve(&mut upd, slots)?;
232 upd.extend_from_slice(pos);
233 for v in 0..slots as u32 {
234 if !vlive[v as usize] {
235 continue;
236 }
237 let p = f64v(&pos[v as usize]);
238 let b = &bnd[v as usize];
239 if !b.is_empty() {
240 if b.len() == 2 {
243 let q0 = f64v(&pos[b[0] as usize]);
244 let q1 = f64v(&pos[b[1] as usize]);
245 let q = [0, 1, 2].map(|k| 0.75 * p[k] + 0.125 * (q0[k] + q1[k]));
246 upd[v as usize] = [q[0] as f32, q[1] as f32, q[2] as f32];
247 }
248 continue;
249 }
250 let n = nbs[v as usize].len();
251 if n == 0 {
252 continue;
253 }
254 let beta = loop_beta(n);
255 let mut q = [0, 1, 2].map(|k| (1.0 - n as f64 * beta) * p[k]);
256 for &w in &nbs[v as usize] {
257 let r = f64v(&pos[w as usize]);
258 for k in 0..3 {
259 q[k] += beta * r[k];
260 }
261 }
262 upd[v as usize] = [q[0] as f32, q[1] as f32, q[2] as f32];
263 }
264
265 let mut edge_point: Vec<[f32; 3]> = Vec::new();
267 reserve(&mut edge_point, edges.len())?;
268 for (k, &(a, b)) in edges.iter().enumerate() {
269 let pa = f64v(&pos[a as usize]);
270 let pb = f64v(&pos[b as usize]);
271 let q = if owners[k] == 2 {
272 let pc = f64v(&pos[apexes[k][0] as usize]);
273 let pd = f64v(&pos[apexes[k][1] as usize]);
274 [0, 1, 2].map(|i| 0.375 * (pa[i] + pb[i]) + 0.125 * (pc[i] + pd[i]))
275 } else {
276 [0, 1, 2].map(|i| 0.5 * (pa[i] + pb[i]))
277 };
278 push(&mut edge_point, [q[0] as f32, q[1] as f32, q[2] as f32])?;
279 }
280
281 let degenerate = tris.len() - clean;
283 let mut next: Vec<WorkTri> = Vec::new();
284 reserve(
285 &mut next,
286 clean
287 .checked_mul(4)
288 .and_then(|n| n.checked_add(degenerate))
289 .ok_or(crate::OpsError::Store(
290 fast_mesh_store::StoreError::OutOfMemory,
291 ))?,
292 )?;
293 let edge_id = |a: u32, b: u32| -> u32 {
295 let k = edges.binary_search(&key(a, b)).expect("edge must exist");
296 slots as u32 + k as u32
297 };
298 for tri in tris.iter() {
299 if !tri.clean {
300 push(
301 &mut next,
302 WorkTri {
303 slot: tri.slot,
304 corners: tri.corners,
305 clean: false,
306 },
307 )?;
308 continue;
309 }
310 let [a, b, c] = tri.corners;
311 let (ab, bc, ca) = (edge_id(a, b), edge_id(b, c), edge_id(c, a));
312 let children = [[a, ab, ca], [b, bc, ab], [c, ca, bc], [ab, bc, ca]];
313 for (j, corners) in children.into_iter().enumerate() {
314 push(
315 &mut next,
316 WorkTri {
317 slot: if j == 0 { tri.slot } else { None },
318 corners,
319 clean: true,
320 },
321 )?;
322 }
323 }
324
325 if let Some(uv) = uvs {
326 reserve(uv, 2 * edges.len())?;
327 for &(a, b) in &edges {
328 let (ia, ib) = (2 * a as usize, 2 * b as usize);
329 let mid = [0, 1].map(|c| 0.5 * (uv[ia + c] + uv[ib + c]));
330 uv.extend_from_slice(&mid);
331 }
332 }
333 *pos = upd;
334 reserve(pos, edge_point.len())?;
335 pos.extend_from_slice(&edge_point);
336 reserve(vlive, edge_point.len())?;
337 vlive.resize(vlive.len() + edge_point.len(), true);
338 *tris = next;
339 Ok(true)
340}
341
342pub fn subdivide(tx: &mut Transaction, options: &SubdivideOptions) -> Result<SubdivideReport> {
354 if options.levels == 0 {
355 return Err(OpsError::InvalidInput(
356 "subdivide levels must be at least 1",
357 ));
358 }
359 let _ = options.method;
360 let mesh = tx.mesh();
361 let slots = mesh.vertex_slots();
362 let mut pos: Vec<[f32; 3]> = Vec::new();
363 reserve(&mut pos, slots)?;
364 pos.extend_from_slice(mesh.positions());
365 let mut vlive: Vec<bool> = Vec::new();
366 reserve(&mut vlive, slots)?;
367 vlive.extend((0..slots as u32).map(|v| mesh.is_vertex_alive(v as VertexId)));
368 let mut tris: Vec<WorkTri> = Vec::new();
369 reserve(&mut tris, mesh.triangle_slots())?;
370 for t in 0..mesh.triangle_slots() as u32 {
371 let Some(corners) = mesh.triangle(t) else {
372 continue;
373 };
374 push(
375 &mut tris,
376 WorkTri {
377 slot: Some(t),
378 corners,
379 clean: corners[0] != corners[1]
380 && corners[1] != corners[2]
381 && corners[2] != corners[0],
382 },
383 )?;
384 }
385
386 let mut uvs: Option<Vec<f32>> = None;
388 if let Some(from) = mesh.uvs() {
389 let mut copy = Vec::new();
390 reserve(&mut copy, from.len())?;
391 copy.extend_from_slice(from);
392 uvs = Some(copy);
393 }
394 let mut subdivided = false;
395 for _ in 0..options.levels {
396 if !step(&mut pos, &mut vlive, &mut tris, uvs.as_mut())? {
397 break;
398 }
399 subdivided = true;
400 }
401 if !subdivided {
402 return Ok(SubdivideReport::default());
403 }
404
405 let base = mesh.positions();
408 let mut set_p: Vec<VertexId> = Vec::new();
409 let mut set_p_to: Vec<[f32; 3]> = Vec::new();
410 let mut new_p: Vec<[f32; 3]> = Vec::new();
411 let mut set_t: Vec<u32> = Vec::new();
412 let mut set_t_to: Vec<[u32; 3]> = Vec::new();
413 let mut add_t: Vec<[u32; 3]> = Vec::new();
414 let mut n_moved = 0;
415 for v in 0..slots as u32 {
416 if vlive[v as usize] && (v as usize) < pos.len() && pos[v as usize] != base[v as usize] {
417 n_moved += 1;
418 }
419 }
420 for v in slots..pos.len() {
421 if vlive[v] {
422 reserve(&mut new_p, 1)?;
423 push(&mut new_p, pos[v])?;
424 }
425 }
426 reserve(&mut set_p, n_moved)?;
427 reserve(&mut set_p_to, n_moved)?;
428 let mut n_set_t = 0;
429 let mut n_add_t = 0;
430 for tri in &tris {
431 if tri.slot.is_some() {
432 n_set_t += 1;
433 } else {
434 n_add_t += 1;
435 }
436 }
437 reserve(&mut set_t, n_set_t)?;
438 reserve(&mut set_t_to, n_set_t)?;
439 reserve(&mut add_t, n_add_t)?;
440 for v in 0..slots as u32 {
441 if vlive[v as usize] && pos[v as usize] != base[v as usize] {
442 set_p.push(v as VertexId);
443 set_p_to.push(pos[v as usize]);
444 }
445 }
446 for tri in &tris {
447 if let Some(slot) = tri.slot {
448 set_t.push(slot);
449 set_t_to.push(tri.corners);
450 } else {
451 add_t.push(tri.corners);
452 }
453 }
454 let mut real: Vec<u32> = Vec::new();
457 reserve(&mut real, pos.len())?;
458 let mut set_mapped: Vec<[VertexId; 3]> = Vec::new();
459 reserve(&mut set_mapped, set_t_to.len())?;
460 let mut add_mapped: Vec<[VertexId; 3]> = Vec::new();
461 reserve(&mut add_mapped, add_t.len())?;
462 tx.set_positions(&set_p, &set_p_to)?;
463 let added = tx.add_vertices(&new_p)?;
468 real.extend(0..pos.len() as u32);
469 {
470 let mut k = 0;
471 for v in slots..pos.len() {
472 if vlive[v] {
473 real[v] = added[k];
474 k += 1;
475 }
476 }
477 }
478 let map = |c: [u32; 3]| c.map(|v| real[v as usize] as VertexId);
479 set_mapped.extend(set_t_to.iter().map(|&c| map(c)));
480 add_mapped.extend(add_t.iter().map(|&c| map(c)));
481 if let Some(uv) = &uvs {
482 tx.write_channel(UV_CHANNEL, &added, &uv[2 * slots..])?;
483 }
484 tx.set_triangles(&set_t, &set_mapped)?;
485 tx.add_triangles(&add_mapped)?;
486 Ok(SubdivideReport {
487 vertices_added: added.len(),
488 triangles_added: add_mapped.len(),
489 })
490}
491
492#[cfg(test)]
493mod tests {
494 use fast_mesh_store::{Mesh, Transaction, VertexId};
495
496 use super::*;
497 use crate::test_util::{box_mesh, edit, grid, mesh_of, parts, sweep};
498
499 fn live_count(mesh: &Mesh) -> usize {
500 (0..mesh.triangle_slots() as u32)
501 .filter(|&t| mesh.triangle(t).is_some())
502 .count()
503 }
504
505 fn live_vertices(mesh: &Mesh) -> usize {
506 (0..mesh.vertex_slots() as u32)
507 .filter(|&v| mesh.is_vertex_alive(v as VertexId))
508 .count()
509 }
510
511 fn edge_counts(mesh: &Mesh) -> (usize, usize) {
513 let mut pairs = Vec::new();
514 for t in 0..mesh.triangle_slots() as u32 {
515 if let Some(c) = mesh.triangle(t) {
516 if c[0] == c[1] || c[1] == c[2] || c[2] == c[0] {
517 continue;
518 }
519 for k in 0..3 {
520 pairs.push(key(c[k], c[(k + 1) % 3]));
521 }
522 }
523 }
524 pairs.sort_unstable();
525 let mut unique = 0;
526 let mut boundary = 0;
527 let mut start = 0;
528 while start < pairs.len() {
529 let mut end = start + 1;
530 while end < pairs.len() && pairs[end] == pairs[start] {
531 end += 1;
532 }
533 unique += 1;
534 if end - start == 1 {
535 boundary += 1;
536 }
537 start = end;
538 }
539 (unique, boundary)
540 }
541
542 fn assert_no_degenerate(mesh: &Mesh) {
543 for t in 0..mesh.triangle_slots() as u32 {
544 if let Some(c) = mesh.triangle(t) {
545 assert!(
546 c[0] != c[1] && c[1] != c[2] && c[2] != c[0],
547 "degenerate: {c:?}"
548 );
549 for &v in &c {
550 assert!(mesh.is_vertex_alive(v as VertexId));
551 }
552 }
553 }
554 }
555
556 #[test]
557 fn cube_quadruples_closed() {
558 let mut mesh = box_mesh([0.0; 3], [1.0; 3]);
559 assert_eq!(live_count(&mesh), 12);
560 let (unique, boundary) = edge_counts(&mesh);
561 assert_eq!(boundary, 0);
562 let options = SubdivideOptions::builder().levels(1).build();
563 let (report, empty) = edit(&mut mesh, |tx| subdivide(tx, &options));
564 assert!(!empty);
565 assert_eq!(live_count(&mesh), 48);
566 assert_eq!(live_vertices(&mesh), 8 + unique);
567 assert_eq!(report.vertices_added, unique);
568 assert_eq!(report.triangles_added, 36);
569 assert_no_degenerate(&mesh);
570 }
571
572 #[test]
573 fn plane_quadruples_and_stays_planar() {
574 let mut mesh = grid(2);
578 assert_eq!(live_count(&mesh), 8);
579 let (unique, boundary) = edge_counts(&mesh);
580 assert_eq!(boundary, 8);
581 let options = SubdivideOptions::builder().levels(1).build();
582 let (report, empty) = edit(&mut mesh, |tx| subdivide(tx, &options));
583 assert!(!empty);
584 assert_eq!(live_count(&mesh), 32);
585 assert_eq!(live_vertices(&mesh), 9 + unique);
586 assert_eq!(report.vertices_added, unique);
587 assert_eq!(report.triangles_added, 24);
588 for v in 0..mesh.vertex_slots() as u32 {
589 if mesh.is_vertex_alive(v as VertexId) {
590 assert_eq!(mesh.positions()[v as usize][2], 0.0);
591 }
592 }
593 assert_eq!(edge_counts(&mesh).1, 16);
594 assert_no_degenerate(&mesh);
595 }
596
597 #[test]
598 fn two_levels_multiply_by_sixteen() {
599 let mut mesh = box_mesh([0.0; 3], [1.0; 3]);
600 let options = SubdivideOptions::builder().levels(2).build();
601 let (report, empty) = edit(&mut mesh, |tx| subdivide(tx, &options));
602 assert!(!empty);
603 assert_eq!(live_count(&mesh), 12 * 16);
604 assert_eq!(live_vertices(&mesh), 8 + report.vertices_added);
605 assert_eq!(report.triangles_added, 12 * 16 - 12);
606 assert_no_degenerate(&mesh);
607 }
608
609 #[test]
610 fn invalid_levels_and_noop_mesh() {
611 let mut mesh = box_mesh([0.0; 3], [1.0; 3]);
612 {
613 let mut tx = mesh.begin_edit();
614 assert_eq!(
615 subdivide(&mut tx, &SubdivideOptions::builder().levels(0).build()),
616 Err(OpsError::InvalidInput(
617 "subdivide levels must be at least 1"
618 ))
619 );
620 }
621 let mut empty_mesh = mesh_of(&[], &[]);
623 let before = parts(&empty_mesh);
624 let (report, empty) = edit(&mut empty_mesh, |tx| {
625 subdivide(tx, &SubdivideOptions::builder().levels(1).build())
626 });
627 assert_eq!(
628 (report.vertices_added, report.triangles_added, empty),
629 (0, 0, true)
630 );
631 assert_eq!(parts(&empty_mesh), before);
632 let mut degenerate = mesh_of(&[0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0], &[[0, 0, 1]]);
634 let before = parts(°enerate);
635 let (report, empty) = edit(&mut degenerate, |tx| {
636 subdivide(tx, &SubdivideOptions::builder().levels(1).build())
637 });
638 assert_eq!(
639 (report.vertices_added, report.triangles_added, empty),
640 (0, 0, true)
641 );
642 assert_eq!(parts(°enerate), before);
643 }
644
645 #[test]
646 fn subdivide_sweep_keeps_atomicity() {
647 let n = sweep(grid(2), |tx: &mut Transaction| {
648 subdivide(tx, &SubdivideOptions::builder().levels(1).build())?;
649 Ok(())
650 });
651 assert!(n > 0);
652 }
653}