1use enum_dispatch::enum_dispatch;
21
22use crate::catmull_clark::stencils::{
23 CcLevelData, base_level_data as cc_base_level_data,
24 refine_topology_once as cc_refine_topology_once,
25 vertex_stencils_from_level as cc_vertex_stencils_from_level,
26};
27use crate::doo_sabin::stencils::{
28 DooSabinLevelData, base_level_data as doo_sabin_base_level_data,
29 refine_topology_once as doo_sabin_refine_topology_once,
30 vertex_stencils_from_level as doo_sabin_vertex_stencils_from_level,
31};
32use crate::loop_subdivision::stencils::{
33 LoopLevelData, base_level_data as loop_base_level_data,
34 refine_topology_once as loop_refine_topology_once,
35 vertex_stencils_from_level as loop_vertex_stencils_from_level,
36};
37use crate::sqrt3::stencils::{
38 Sqrt3LevelData, base_level_data as sqrt3_base_level_data,
39 refine_topology_once as sqrt3_refine_topology_once,
40 vertex_stencils_from_level as sqrt3_vertex_stencils_from_level,
41};
42use crate::{
43 Adjacency, FaceVaryingChannel, FaceVaryingInterpolation, KernelError, LineageMaps, Mesh,
44 RefinementResult, Scheme, SchemeOptions, StencilTable, UniformRefine,
45};
46
47#[enum_dispatch]
53pub(crate) trait LevelDataCommon {
54 fn mesh(&self) -> &Mesh;
55 fn lineage(&self) -> &LineageMaps;
56 fn face_selected(&self) -> &[bool];
57 fn adjacency(&self) -> &Adjacency;
58}
59
60#[enum_dispatch(LevelDataCommon)]
68pub(crate) enum LevelData {
69 Cc(CcLevelData),
70 Loop(LoopLevelData),
71 Sqrt3(Sqrt3LevelData),
72 DooSabin(DooSabinLevelData),
73}
74
75pub struct Refiner {
92 topology: Mesh,
93 scheme: Scheme,
94 options: SchemeOptions,
95}
96
97#[must_use]
111pub struct Refinement {
112 levels: Vec<LevelData>,
116 scheme: Scheme,
117 options: SchemeOptions,
118 edge_polylines: Option<Vec<Vec<u32>>>,
120}
121
122#[non_exhaustive]
137pub struct RefinedFinalParts {
138 pub topology: Mesh,
140 pub lineage: LineageMaps,
142 pub adjacency: Adjacency,
144 pub selected_faces: Option<Vec<bool>>,
146 pub edge_polylines: Option<Vec<Vec<u32>>>,
148}
149
150impl Refinement {
151 #[must_use]
153 pub fn scheme(&self) -> Scheme {
154 self.scheme
155 }
156
157 pub fn vertex_stencils(&self) -> Vec<StencilTable> {
171 let parent_count = self.levels.len().saturating_sub(1);
174 (0..parent_count)
175 .map(|k| match &self.levels[k] {
176 LevelData::Cc(parent) => cc_vertex_stencils_from_level(parent, &self.options),
177 LevelData::Loop(parent) => loop_vertex_stencils_from_level(parent, &self.options),
178 LevelData::Sqrt3(parent) => sqrt3_vertex_stencils_from_level(parent, &self.options),
179 LevelData::DooSabin(parent) => {
180 doo_sabin_vertex_stencils_from_level(parent, &self.options)
181 }
182 })
183 .collect()
184 }
185
186 pub fn face_varying_stencils(
192 &self,
193 channel: &FaceVaryingChannel,
194 mode: FaceVaryingInterpolation,
195 ) -> Result<Vec<StencilTable>, KernelError> {
196 let level_count = self.levels.len().saturating_sub(1);
197 let mut tables = Vec::with_capacity(level_count);
198 let mut current_fvar = channel.clone();
199
200 for i in 0..level_count {
201 let table = match (&self.levels[i], &self.levels[i + 1]) {
202 (LevelData::Cc(parent), LevelData::Cc(child)) => {
203 crate::catmull_clark::face_varying::fvar_stencils_once(
204 parent,
205 child,
206 ¤t_fvar,
207 mode,
208 &self.options,
209 )?
210 }
211 (LevelData::Loop(parent), LevelData::Loop(child)) => {
212 crate::loop_subdivision::face_varying::fvar_stencils_once(
213 parent,
214 child,
215 ¤t_fvar,
216 mode,
217 &self.options,
218 )?
219 }
220 (LevelData::Sqrt3(parent), LevelData::Sqrt3(child)) => {
221 crate::sqrt3::face_varying::fvar_stencils_once(
222 parent,
223 child,
224 ¤t_fvar,
225 mode,
226 &self.options,
227 )?
228 }
229 (LevelData::DooSabin(parent), LevelData::DooSabin(child)) => {
230 crate::doo_sabin::face_varying::fvar_stencils_once(
231 parent,
232 child,
233 ¤t_fvar,
234 mode,
235 &self.options,
236 )?
237 }
238 _ => unreachable!("a refinement chain holds one scheme's level data throughout"),
239 };
240 tables.push(table);
241
242 current_fvar = identity_channel(self.levels[i + 1].mesh());
243 }
244
245 Ok(tables)
246 }
247
248 pub fn final_topology(&self) -> &Mesh {
250 self.levels.last().expect("at least one level").mesh()
251 }
252
253 pub fn lineage(&self) -> &LineageMaps {
255 self.levels.last().expect("at least one level").lineage()
256 }
257
258 pub fn adjacency(&self) -> &Adjacency {
260 self.levels.last().expect("at least one level").adjacency()
261 }
262
263 pub fn edge_polylines(&self) -> Option<&[Vec<u32>]> {
266 self.edge_polylines.as_deref()
267 }
268
269 pub fn selected_faces(&self) -> Option<&[bool]> {
271 if self.levels.len() <= 1 {
279 return None;
280 }
281 Some(
282 self.levels
283 .last()
284 .expect("at least one level")
285 .face_selected(),
286 )
287 }
288
289 pub fn refinement_steps(&self) -> usize {
291 self.levels.len().saturating_sub(1)
292 }
293
294 pub fn level_lineage(&self, step: usize) -> Option<&LineageMaps> {
304 self.levels.get(step + 1).map(|level| level.lineage())
307 }
308
309 pub fn into_final_parts(mut self) -> RefinedFinalParts {
320 let last = self.levels.pop().expect("at least one level");
321 let refinement_ran = !self.levels.is_empty();
325 match last {
326 LevelData::Cc(level) => RefinedFinalParts {
327 topology: level.mesh,
328 lineage: level.lineage,
329 adjacency: level.adjacency,
330 selected_faces: refinement_ran.then_some(level.face_selected),
331 edge_polylines: self.edge_polylines,
332 },
333 LevelData::Loop(level) => RefinedFinalParts {
334 topology: level.mesh,
335 lineage: level.lineage,
336 adjacency: level.adjacency,
337 selected_faces: refinement_ran.then_some(level.face_selected),
338 edge_polylines: self.edge_polylines,
339 },
340 LevelData::Sqrt3(level) => RefinedFinalParts {
341 topology: level.mesh,
342 lineage: level.lineage,
343 adjacency: level.adjacency,
344 selected_faces: refinement_ran.then_some(level.face_selected),
345 edge_polylines: self.edge_polylines,
346 },
347 LevelData::DooSabin(level) => RefinedFinalParts {
348 topology: level.mesh,
349 lineage: level.lineage,
350 adjacency: level.adjacency,
351 selected_faces: refinement_ran.then_some(level.face_selected),
352 edge_polylines: self.edge_polylines,
353 },
354 }
355 }
356}
357
358impl Refiner {
359 pub fn new(
361 topology: Mesh,
362 scheme: Scheme,
363 options: SchemeOptions,
364 ) -> Result<Self, KernelError> {
365 topology.validate()?;
366 Ok(Self {
367 topology,
368 scheme,
369 options,
370 })
371 }
372
373 pub fn topology(&self) -> &Mesh {
375 &self.topology
376 }
377
378 pub fn scheme(&self) -> Scheme {
380 self.scheme
381 }
382
383 pub fn options(&self) -> &SchemeOptions {
385 &self.options
386 }
387
388 pub fn refine_topology(&self, req: &UniformRefine) -> Result<Refinement, KernelError> {
395 match self.scheme {
396 Scheme::CatmullClark => self.refine_topology_cc(req),
397 Scheme::Loop => self.refine_topology_loop(req),
398 Scheme::Sqrt3 => self.refine_topology_sqrt3(req),
399 Scheme::DooSabin => self.refine_topology_doo_sabin(req),
400 }
401 }
402
403 fn active_selection(&self, req: &UniformRefine) -> Result<Vec<bool>, KernelError> {
404 let initial_face_count = self.topology.face_vertex_counts.len();
405 req.selected_faces
406 .as_ref()
407 .map(|m| {
408 (m.len() == initial_face_count).then(|| m.clone()).ok_or(
409 KernelError::InvalidTopology(
410 "selected-face mask length does not match face count",
411 ),
412 )
413 })
414 .transpose()
415 .map(|opt| opt.unwrap_or_else(|| vec![true; initial_face_count]))
416 }
417
418 fn refine_topology_cc(&self, req: &UniformRefine) -> Result<Refinement, KernelError> {
419 let active_sel = self.active_selection(req)?;
420 let base = cc_base_level_data(&self.topology, active_sel, req.selection_boundary_crease)?;
421
422 let mut levels: Vec<LevelData> = Vec::with_capacity(req.levels.get() as usize + 1);
423 levels.push(LevelData::Cc(base));
424
425 let mut polylines = req.edge_polylines.then(|| {
426 self.topology
427 .edge_vertices
428 .iter()
429 .map(|&[v0, v1]| vec![v0, v1])
430 .collect::<Vec<_>>()
431 });
432
433 for _ in 0..req.levels.get() {
434 let parent = match levels.last().unwrap() {
435 LevelData::Cc(p) => p,
436 _ => unreachable!("CC refine push-chain only touches CC variants"),
437 };
438 let child =
439 cc_refine_topology_once(parent, &self.options, req.selection_boundary_crease)?;
440
441 if let Some(ref mut polys) = polylines {
442 Self::refine_polylines(polys, &child.lineage, &parent.mesh);
443 }
444
445 levels.push(LevelData::Cc(child));
446 }
447
448 Ok(Refinement {
449 levels,
450 scheme: self.scheme,
451 options: self.options,
452 edge_polylines: polylines,
453 })
454 }
455
456 fn refine_topology_loop(&self, req: &UniformRefine) -> Result<Refinement, KernelError> {
457 let active_sel = self.active_selection(req)?;
458 let base = loop_base_level_data(
459 &self.topology,
460 active_sel,
461 &self.options,
462 req.selection_boundary_crease,
463 )?;
464
465 let mut levels: Vec<LevelData> = Vec::with_capacity(req.levels.get() as usize + 1);
466 levels.push(LevelData::Loop(base));
467
468 let mut polylines = req.edge_polylines.then(|| {
469 self.topology
470 .edge_vertices
471 .iter()
472 .map(|&[v0, v1]| vec![v0, v1])
473 .collect::<Vec<_>>()
474 });
475
476 for _ in 0..req.levels.get() {
477 let parent = match levels.last().unwrap() {
478 LevelData::Loop(p) => p,
479 _ => unreachable!("Loop refine push-chain only touches Loop variants"),
480 };
481 let child =
482 loop_refine_topology_once(parent, &self.options, req.selection_boundary_crease)?;
483
484 if let Some(ref mut polys) = polylines {
485 Self::refine_polylines(polys, &child.lineage, &parent.mesh);
486 }
487
488 levels.push(LevelData::Loop(child));
489 }
490
491 Ok(Refinement {
492 levels,
493 scheme: self.scheme,
494 options: self.options,
495 edge_polylines: polylines,
496 })
497 }
498
499 fn refine_topology_sqrt3(&self, req: &UniformRefine) -> Result<Refinement, KernelError> {
500 let active_sel = self.active_selection(req)?;
501 let base =
502 sqrt3_base_level_data(&self.topology, active_sel, req.selection_boundary_crease)?;
503
504 let mut levels: Vec<LevelData> = Vec::with_capacity(req.levels.get() as usize + 1);
505 levels.push(LevelData::Sqrt3(base));
506
507 let mut polylines = req.edge_polylines.then(|| {
508 self.topology
509 .edge_vertices
510 .iter()
511 .map(|&[v0, v1]| vec![v0, v1])
512 .collect::<Vec<_>>()
513 });
514
515 for _ in 0..req.levels.get() {
516 let parent = match levels.last().unwrap() {
517 LevelData::Sqrt3(p) => p,
518 _ => unreachable!("Sqrt3 refine push-chain only touches Sqrt3 variants"),
519 };
520 let child =
521 sqrt3_refine_topology_once(parent, &self.options, req.selection_boundary_crease)?;
522
523 if let Some(ref mut polys) = polylines {
524 Self::refine_polylines(polys, &child.lineage, &parent.mesh);
525 }
526
527 levels.push(LevelData::Sqrt3(child));
528 }
529
530 Ok(Refinement {
531 levels,
532 scheme: self.scheme,
533 options: self.options,
534 edge_polylines: polylines,
535 })
536 }
537
538 fn refine_topology_doo_sabin(&self, req: &UniformRefine) -> Result<Refinement, KernelError> {
539 let active_sel = self.active_selection(req)?;
540 let base =
541 doo_sabin_base_level_data(&self.topology, active_sel, req.selection_boundary_crease)?;
542
543 let mut levels: Vec<LevelData> = Vec::with_capacity(req.levels.get() as usize + 1);
544 levels.push(LevelData::DooSabin(base));
545
546 let polylines: Option<Vec<Vec<u32>>> = None;
553
554 for _ in 0..req.levels.get() {
555 let parent = match levels.last().unwrap() {
556 LevelData::DooSabin(p) => p,
557 _ => unreachable!("DooSabin refine push-chain only touches DooSabin variants"),
558 };
559 let child = doo_sabin_refine_topology_once(
560 parent,
561 &self.options,
562 req.selection_boundary_crease,
563 )?;
564
565 levels.push(LevelData::DooSabin(child));
566 }
567
568 Ok(Refinement {
569 levels,
570 scheme: self.scheme,
571 options: self.options,
572 edge_polylines: polylines,
573 })
574 }
575
576 pub fn refine_uniform(&self, req: &UniformRefine) -> Result<RefinementResult, KernelError> {
583 let refined = self.refine_topology(req)?;
584 let level_stencils = refined.vertex_stencils();
585 let face_root = {
589 let base_faces = self.topology.face_vertex_counts.len() as u32;
590 let mut root: Vec<u32> = (0..base_faces).collect();
591 for step in 0..refined.refinement_steps() {
592 let lineage = refined
593 .level_lineage(step)
594 .expect("refinement_steps bounds level_lineage");
595 root = lineage
596 .face_parent
597 .iter()
598 .map(|&parent| root[parent as usize])
599 .collect();
600 }
601 root
602 };
603 Ok(RefinementResult {
604 topology: refined.final_topology().clone(),
605 level_stencils,
606 lineage: refined.lineage().clone(),
607 face_root,
608 selected_faces: refined.selected_faces().map(|s| s.to_vec()),
609 edge_polylines: refined.edge_polylines().map(|p| p.to_vec()),
610 adjacency: refined.adjacency().clone(),
611 scheme: self.scheme,
612 options: self.options,
613 })
614 }
615
616 fn refine_polylines(polylines: &mut [Vec<u32>], lineage: &LineageMaps, parent_topo: &Mesh) {
620 use crate::output::VertexOrigin;
621
622 let edge_point_for_parent: Vec<Option<u32>> = {
624 let edge_count = parent_topo.edge_vertices.len();
625 let mut map = vec![None; edge_count];
626 lineage
627 .vertex_origin
628 .iter()
629 .enumerate()
630 .for_each(|(vi, origin)| {
631 if let VertexOrigin::Edge(parent_ei) = *origin {
632 map[parent_ei as usize] = Some(vi as u32);
633 }
634 });
635 map
636 };
637
638 let edge_key = |a: u32, b: u32| if a <= b { (a, b) } else { (b, a) };
640 let edge_key_to_idx: rustc_hash::FxHashMap<(u32, u32), usize> = parent_topo
641 .edge_vertices
642 .iter()
643 .enumerate()
644 .map(|(ei, &[v0, v1])| (edge_key(v0, v1), ei))
645 .collect();
646
647 let vertex_point_for_parent: Vec<Option<u32>> = {
649 let vert_count = parent_topo.vertex_count as usize;
650 let mut map = vec![None; vert_count];
651 lineage
652 .vertex_origin
653 .iter()
654 .enumerate()
655 .for_each(|(vi, origin)| {
656 if let VertexOrigin::Vertex(parent_vi) = *origin {
657 map[parent_vi as usize] = Some(vi as u32);
658 }
659 });
660 map
661 };
662
663 polylines.iter_mut().for_each(|poly| {
664 let mut new_poly = Vec::with_capacity(poly.len() * 2);
665
666 poly.windows(2).for_each(|pair| {
667 let a = pair[0];
668 let b = pair[1];
669
670 let ra = vertex_point_for_parent
671 .get(a as usize)
672 .copied()
673 .flatten()
674 .unwrap_or(a);
675
676 new_poly.push(ra);
677
678 let key = edge_key(a, b);
679 if let Some(&ei) = edge_key_to_idx.get(&key) {
680 if let Some(ep) = edge_point_for_parent[ei] {
681 new_poly.push(ep);
682 }
683 }
684 });
685
686 if let Some(&last) = poly.last() {
687 let rl = vertex_point_for_parent
688 .get(last as usize)
689 .copied()
690 .flatten()
691 .unwrap_or(last);
692 new_poly.push(rl);
693 }
694
695 *poly = new_poly;
696 });
697 }
698
699 pub fn face_varying_stencils(
712 &self,
713 req: &UniformRefine,
714 channel: &FaceVaryingChannel,
715 mode: FaceVaryingInterpolation,
716 ) -> Result<Vec<StencilTable>, KernelError> {
717 match self.scheme {
718 Scheme::CatmullClark => self.face_varying_stencils_cc(req, channel, mode),
719 Scheme::Loop => self.face_varying_stencils_loop(req, channel, mode),
720 Scheme::Sqrt3 => self.face_varying_stencils_sqrt3(req, channel, mode),
721 Scheme::DooSabin => self.face_varying_stencils_doo_sabin(req, channel, mode),
722 }
723 }
724
725 fn face_varying_stencils_loop(
726 &self,
727 req: &UniformRefine,
728 channel: &FaceVaryingChannel,
729 mode: FaceVaryingInterpolation,
730 ) -> Result<Vec<StencilTable>, KernelError> {
731 use crate::loop_subdivision::face_varying::fvar_stencils_once;
732
733 let active_sel = self.active_selection(req)?;
734 let mut parent = loop_base_level_data(
735 &self.topology,
736 active_sel,
737 &self.options,
738 req.selection_boundary_crease,
739 )?;
740 let mut current_fvar = channel.clone();
741 let mut tables = Vec::with_capacity(req.levels.get() as usize);
742
743 for _ in 0..req.levels.get() {
744 let child =
745 loop_refine_topology_once(&parent, &self.options, req.selection_boundary_crease)?;
746 tables.push(fvar_stencils_once(
747 &parent,
748 &child,
749 ¤t_fvar,
750 mode,
751 &self.options,
752 )?);
753 current_fvar = identity_channel(&child.mesh);
754 parent = child;
755 }
756
757 Ok(tables)
758 }
759
760 fn face_varying_stencils_sqrt3(
761 &self,
762 req: &UniformRefine,
763 channel: &FaceVaryingChannel,
764 mode: FaceVaryingInterpolation,
765 ) -> Result<Vec<StencilTable>, KernelError> {
766 use crate::sqrt3::face_varying::fvar_stencils_once;
767
768 let active_sel = self.active_selection(req)?;
769 let mut parent =
770 sqrt3_base_level_data(&self.topology, active_sel, req.selection_boundary_crease)?;
771 let mut current_fvar = channel.clone();
772 let mut tables = Vec::with_capacity(req.levels.get() as usize);
773
774 for _ in 0..req.levels.get() {
775 let child =
776 sqrt3_refine_topology_once(&parent, &self.options, req.selection_boundary_crease)?;
777 tables.push(fvar_stencils_once(
778 &parent,
779 &child,
780 ¤t_fvar,
781 mode,
782 &self.options,
783 )?);
784 current_fvar = identity_channel(&child.mesh);
785 parent = child;
786 }
787
788 Ok(tables)
789 }
790
791 fn face_varying_stencils_doo_sabin(
792 &self,
793 req: &UniformRefine,
794 channel: &FaceVaryingChannel,
795 mode: FaceVaryingInterpolation,
796 ) -> Result<Vec<StencilTable>, KernelError> {
797 use crate::doo_sabin::face_varying::fvar_stencils_once;
798
799 let active_sel = self.active_selection(req)?;
800 let mut parent =
801 doo_sabin_base_level_data(&self.topology, active_sel, req.selection_boundary_crease)?;
802 let mut current_fvar = channel.clone();
803 let mut tables = Vec::with_capacity(req.levels.get() as usize);
804
805 for _ in 0..req.levels.get() {
806 let child = doo_sabin_refine_topology_once(
807 &parent,
808 &self.options,
809 req.selection_boundary_crease,
810 )?;
811 tables.push(fvar_stencils_once(
812 &parent,
813 &child,
814 ¤t_fvar,
815 mode,
816 &self.options,
817 )?);
818 current_fvar = identity_channel(&child.mesh);
819 parent = child;
820 }
821
822 Ok(tables)
823 }
824
825 fn face_varying_stencils_cc(
826 &self,
827 req: &UniformRefine,
828 channel: &FaceVaryingChannel,
829 mode: FaceVaryingInterpolation,
830 ) -> Result<Vec<StencilTable>, KernelError> {
831 use crate::catmull_clark::face_varying::fvar_stencils_once;
832
833 let active_sel = self.active_selection(req)?;
834 let mut current_level =
835 cc_base_level_data(&self.topology, active_sel, req.selection_boundary_crease)?;
836 let mut current_fvar = channel.clone();
837 let mut tables = Vec::with_capacity(req.levels.get() as usize);
838
839 for _ in 0..req.levels.get() {
840 let child = cc_refine_topology_once(
841 ¤t_level,
842 &self.options,
843 req.selection_boundary_crease,
844 )?;
845
846 tables.push(fvar_stencils_once(
847 ¤t_level,
848 &child,
849 ¤t_fvar,
850 mode,
851 &self.options,
852 )?);
853
854 current_fvar = identity_channel(&child.mesh);
855 current_level = child;
856 }
857
858 Ok(tables)
859 }
860}
861
862fn identity_channel(mesh: &Mesh) -> FaceVaryingChannel {
866 let n: u32 = mesh.face_vertex_counts.iter().sum();
867 FaceVaryingChannel {
868 indices: (0..n).collect(),
869 value_count: n,
870 }
871}