1use glam::{Vec2, Vec3, Vec4};
4use std::collections::HashMap;
5use super::GeoMesh;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum SubdivisionScheme {
10 CatmullClark,
12 Loop,
14 Midpoint,
16}
17
18#[derive(Debug, Clone)]
20pub struct SubdivMesh {
21 pub vertices: Vec<Vec3>,
22 pub faces: Vec<Vec<u32>>, }
24
25impl SubdivMesh {
26 pub fn new() -> Self { Self { vertices: Vec::new(), faces: Vec::new() } }
27
28 pub fn from_geo_mesh(mesh: &GeoMesh) -> Self {
29 let vertices = mesh.vertices.clone();
30 let faces: Vec<Vec<u32>> = mesh.triangles.iter()
31 .map(|t| vec![t.a, t.b, t.c])
32 .collect();
33 Self { vertices, faces }
34 }
35
36 pub fn subdivide(&self, scheme: SubdivisionScheme) -> SubdivMesh {
38 match scheme {
39 SubdivisionScheme::CatmullClark => self.catmull_clark(),
40 SubdivisionScheme::Loop => self.loop_subdivide(),
41 SubdivisionScheme::Midpoint => self.midpoint_subdivide(),
42 }
43 }
44
45 pub fn subdivide_n(&self, scheme: SubdivisionScheme, levels: u32) -> SubdivMesh {
47 let mut mesh = self.clone();
48 for _ in 0..levels {
49 mesh = mesh.subdivide(scheme);
50 }
51 mesh
52 }
53
54 fn catmull_clark(&self) -> SubdivMesh {
55 let n_verts = self.vertices.len();
56 let mut new_verts: Vec<Vec3> = Vec::new();
57 let mut new_faces: Vec<Vec<u32>> = Vec::new();
58
59 let mut face_points = Vec::with_capacity(self.faces.len());
61 for face in &self.faces {
62 let avg = face.iter()
63 .map(|&i| self.vertices[i as usize])
64 .fold(Vec3::ZERO, |a, b| a + b) / face.len() as f32;
65 face_points.push(new_verts.len() as u32);
66 new_verts.push(avg);
67 }
68
69 let mut edge_map: HashMap<(u32, u32), u32> = HashMap::new();
71 let mut edge_faces: HashMap<(u32, u32), Vec<usize>> = HashMap::new();
72
73 for (fi, face) in self.faces.iter().enumerate() {
74 for i in 0..face.len() {
75 let a = face[i];
76 let b = face[(i + 1) % face.len()];
77 let key = if a < b { (a, b) } else { (b, a) };
78 edge_faces.entry(key).or_default().push(fi);
79 }
80 }
81
82 for (&(a, b), faces) in &edge_faces {
83 let mid = (self.vertices[a as usize] + self.vertices[b as usize]) * 0.5;
84 let face_avg: Vec3 = faces.iter()
85 .map(|&fi| new_verts[face_points[fi] as usize])
86 .fold(Vec3::ZERO, |acc, v| acc + v) / faces.len() as f32;
87 let edge_point = (mid + face_avg) * 0.5;
88 let idx = new_verts.len() as u32;
89 new_verts.push(edge_point);
90 edge_map.insert((a, b), idx);
91 }
92
93 let orig_offset = new_verts.len() as u32;
95 for (vi, &vert) in self.vertices.iter().enumerate() {
96 new_verts.push(vert);
98 }
99
100 for (fi, face) in self.faces.iter().enumerate() {
102 let fp = face_points[fi];
103 for i in 0..face.len() {
104 let a = face[i];
105 let b = face[(i + 1) % face.len()];
106 let prev = face[(i + face.len() - 1) % face.len()];
107
108 let key_ab = if a < b { (a, b) } else { (b, a) };
109 let key_pa = if prev < a { (prev, a) } else { (a, prev) };
110
111 let ep_ab = edge_map[&key_ab];
112 let ep_pa = edge_map[&key_pa];
113 let orig_a = orig_offset + a;
114
115 new_faces.push(vec![fp, ep_pa, orig_a, ep_ab]);
116 }
117 }
118
119 SubdivMesh { vertices: new_verts, faces: new_faces }
120 }
121
122 fn loop_subdivide(&self) -> SubdivMesh {
123 let mut new_verts = self.vertices.clone();
125 let mut new_faces = Vec::new();
126 let mut edge_map: HashMap<(u32, u32), u32> = HashMap::new();
127
128 let mut get_edge_vert = |a: u32, b: u32, verts: &mut Vec<Vec3>, orig: &[Vec3]| -> u32 {
129 let key = if a < b { (a, b) } else { (b, a) };
130 if let Some(&idx) = edge_map.get(&key) { return idx; }
131 let mid = (orig[a as usize] + orig[b as usize]) * 0.5;
132 let idx = verts.len() as u32;
133 verts.push(mid);
134 edge_map.insert(key, idx);
135 idx
136 };
137
138 for face in &self.faces {
139 if face.len() != 3 { continue; }
140 let (a, b, c) = (face[0], face[1], face[2]);
141 let ab = get_edge_vert(a, b, &mut new_verts, &self.vertices);
142 let bc = get_edge_vert(b, c, &mut new_verts, &self.vertices);
143 let ca = get_edge_vert(c, a, &mut new_verts, &self.vertices);
144 new_faces.push(vec![a, ab, ca]);
145 new_faces.push(vec![ab, b, bc]);
146 new_faces.push(vec![ca, bc, c]);
147 new_faces.push(vec![ab, bc, ca]);
148 }
149
150 SubdivMesh { vertices: new_verts, faces: new_faces }
151 }
152
153 fn midpoint_subdivide(&self) -> SubdivMesh {
154 self.loop_subdivide()
156 }
157
158 pub fn to_geo_mesh(&self) -> GeoMesh {
160 let mut mesh = GeoMesh::new();
161 for &v in &self.vertices {
162 mesh.add_vertex(v, Vec3::Y, Vec2::ZERO);
163 }
164 for face in &self.faces {
165 if face.len() >= 3 {
166 for i in 1..face.len() - 1 {
168 mesh.add_triangle(face[0], face[i as usize], face[i as usize + 1]);
169 }
170 }
171 }
172 mesh.recompute_normals();
173 mesh
174 }
175
176 pub fn vertex_count(&self) -> usize { self.vertices.len() }
177 pub fn face_count(&self) -> usize { self.faces.len() }
178}
179
180impl Default for SubdivMesh {
181 fn default() -> Self { Self::new() }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 fn make_triangle() -> SubdivMesh {
189 SubdivMesh {
190 vertices: vec![Vec3::ZERO, Vec3::X, Vec3::Y],
191 faces: vec![vec![0, 1, 2]],
192 }
193 }
194
195 #[test]
196 fn loop_subdivision_increases_faces() {
197 let mesh = make_triangle();
198 let subdiv = mesh.subdivide(SubdivisionScheme::Loop);
199 assert_eq!(subdiv.face_count(), 4); assert_eq!(subdiv.vertex_count(), 6); }
202
203 #[test]
204 fn catmull_clark_produces_quads() {
205 let mesh = make_triangle();
206 let subdiv = mesh.subdivide(SubdivisionScheme::CatmullClark);
207 assert!(subdiv.face_count() > 0);
208 for face in &subdiv.faces {
210 assert_eq!(face.len(), 4);
211 }
212 }
213
214 #[test]
215 fn multi_level_subdivision() {
216 let mesh = make_triangle();
217 let subdiv = mesh.subdivide_n(SubdivisionScheme::Loop, 3);
218 assert!(subdiv.face_count() > 16); }
220}