Skip to main content

subdiv_kernels/
options.rs

1/// Rule for sharp/crease/corner vertices. Currently only the OpenSubdiv/DeRose
2/// rule-transition behavior is available.
3#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[non_exhaustive]
6pub enum CornerRule {
7    /// OpenSubdiv / DeRose rule-transition behavior.
8    #[default]
9    OpenSubdivDeRose,
10}
11
12/// Edge sharpness propagation policy.
13#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub enum CreaseComputationMethod {
16    /// Integer decrement style.
17    #[default]
18    Uniform,
19
20    /// Chaikin-inspired smoothing style.
21    Chaikin,
22}
23
24/// Triangle handling mode for Catmull-Clark on triangle faces.
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub enum TriangleSubdivisionRule {
28    /// Catmull-Clark triangle rule.
29    #[default]
30    CatmullClark,
31
32    /// Smooth-triangle variant.
33    SmoothTriangles,
34}
35
36/// Boundary interpolation policy for positional evaluation.
37#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub enum BoundaryInterpolation {
40    /// No boundary-specific handling.
41    Natural,
42
43    /// Interpolate boundary edges only.
44    #[default]
45    EdgesOnly,
46
47    /// Interpolate boundary edges and pin corners.
48    EdgesAndCorners,
49}
50
51/// Face-varying (per-corner, seam-capable) interpolation policy, mirroring
52/// OpenSubdiv's `Sdc::Options::FVarLinearInterpolation` spectrum from fully
53/// linear to fully smooth.
54#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
55#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
56pub enum FaceVaryingInterpolation {
57    /// Linear interpolation everywhere (OSD `FVAR_LINEAR_ALL`); the old
58    /// RenderMan `facevarying` class.
59    Linear,
60
61    /// Smooth interior, linear only at face-varying corners
62    /// (OSD `FVAR_LINEAR_CORNERS_ONLY`).
63    SmoothWithLinearCorners,
64
65    /// Smooth interior, linear along face-varying boundaries/seams
66    /// (OSD `FVAR_LINEAR_BOUNDARIES`). The common default for UV channels:
67    /// smooth within an island, pinned at island seams.
68    #[default]
69    SmoothWithLinearBoundaries,
70
71    /// Smooth subdivision rules everywhere, with seams as smooth boundary
72    /// curves (OSD `FVAR_LINEAR_NONE`); the old RenderMan `facevertex` class.
73    Smooth,
74}
75
76// ── New API types ──────────────────────────────────────────────────────
77
78/// Which subdivision scheme to apply.
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
80#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
81pub enum Scheme {
82    /// Catmull–Clark: quad-based, the film/VFX standard. Accepts any polygons;
83    /// every refined face is a quad.
84    CatmullClark,
85    /// Loop: for triangle meshes. Triangles in, triangles out.
86    Loop,
87    /// √3 (Kobbelt): for triangle meshes. Adds fewer triangles per step than
88    /// Loop and reorients them each level.
89    Sqrt3,
90    /// Doo–Sabin: corner-cutting; produces a new face around each original
91    /// vertex, edge, and face.
92    DooSabin,
93}
94
95/// Scheme-level options that define subdivision behavior.
96///
97/// These are set once when creating a [`Refiner`](crate::Refiner) and
98/// apply to all refinement calls on that refiner.
99#[derive(Debug, Clone, Copy, PartialEq)]
100#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
101pub struct SchemeOptions {
102    /// Sharp-vertex rule selection.
103    pub corner_rule: CornerRule,
104
105    /// Crease propagation mode.
106    pub crease_computation: CreaseComputationMethod,
107
108    /// Positional boundary mode.
109    pub boundary_interpolation: BoundaryInterpolation,
110
111    /// Triangle handling mode (CC only).
112    pub triangle_subdivision_rule: TriangleSubdivisionRule,
113
114    /// Whether to promote vertices with 3+ sharp incident edges.
115    pub auto_corner: bool,
116
117    /// Whether crease values are normalized per level.
118    pub crease_normalize: bool,
119
120    /// Whether corner values are normalized per level.
121    pub corner_normalize: bool,
122}
123
124impl Default for SchemeOptions {
125    fn default() -> Self {
126        Self {
127            corner_rule: CornerRule::default(),
128            crease_computation: CreaseComputationMethod::default(),
129            boundary_interpolation: BoundaryInterpolation::default(),
130            triangle_subdivision_rule: TriangleSubdivisionRule::default(),
131            auto_corner: false,
132            crease_normalize: false,
133            corner_normalize: false,
134        }
135    }
136}
137
138use core::num::NonZeroU8;
139
140/// Per-call refinement parameters.
141#[derive(Debug, Clone, PartialEq)]
142#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
143pub struct UniformRefine {
144    /// Number of uniform refinement levels. Must be at least 1.
145    pub levels: NonZeroU8,
146
147    /// Optional face selection mask. When `Some`, only selected faces are refined.
148    pub selected_faces: Option<Vec<bool>>,
149
150    /// Crease weight applied at selection boundaries.
151    pub selection_boundary_crease: f32,
152
153    /// Track the refined vertices lying along each input edge.
154    ///
155    /// When enabled, the refinement result fills in its `edge_polylines`:
156    /// for every input edge, the refined vertex indices on it, in order.
157    pub edge_polylines: bool,
158}
159
160impl Default for UniformRefine {
161    fn default() -> Self {
162        Self {
163            // SAFETY: 1 is non-zero.
164            levels: NonZeroU8::new(1).unwrap(),
165            selected_faces: None,
166            selection_boundary_crease: 0.0,
167            edge_polylines: false,
168        }
169    }
170}
171
172impl From<NonZeroU8> for UniformRefine {
173    fn from(levels: NonZeroU8) -> Self {
174        Self {
175            levels,
176            ..Self::default()
177        }
178    }
179}