1use ranim_core::{
4 Extract,
5 color::{self, AlphaColor, Srgb},
6 components::rgba::Rgba,
7 core_item::CoreItem,
8 glam::DVec3,
9 traits::{ApplyTransform, FillColor, Interpolatable, Opacity},
10};
11
12use crate::mesh::MeshItem;
13
14use super::{compute_smooth_normals, generate_grid_indices};
15
16fn colorscale_lookup(colorscale: &[(AlphaColor<Srgb>, f64)], value: f64) -> AlphaColor<Srgb> {
18 if colorscale.is_empty() {
19 return color::palette::css::WHITE.with_alpha(1.0);
20 }
21 if value <= colorscale[0].1 {
22 return colorscale[0].0;
23 }
24 if value >= colorscale[colorscale.len() - 1].1 {
25 return colorscale[colorscale.len() - 1].0;
26 }
27 for i in 0..colorscale.len() - 1 {
28 let (c0, v0) = colorscale[i];
29 let (c1, v1) = colorscale[i + 1];
30 if value >= v0 && value <= v1 {
31 let t = ((value - v0) / (v1 - v0)) as f32;
32 let [r0, g0, b0, a0] = c0.components;
33 let [r1, g1, b1, a1] = c1.components;
34 return AlphaColor::new([
35 r0 + (r1 - r0) * t,
36 g0 + (g1 - g0) * t,
37 b0 + (b1 - b0) * t,
38 a0 + (a1 - a0) * t,
39 ]);
40 }
41 }
42 colorscale[colorscale.len() - 1].0
43}
44
45#[derive(Debug, Clone, PartialEq)]
58pub struct Surface {
59 pub vertices: Vec<DVec3>,
61 pub vertex_colors: Vec<AlphaColor<Srgb>>,
63 pub vertex_normals: Vec<DVec3>,
65 pub triangle_indices: Vec<u32>,
67 pub resolution: (u32, u32),
69}
70
71impl Surface {
72 pub fn from_uv_func(
77 uv_func: impl Fn(f64, f64) -> DVec3,
78 u_range: (f64, f64),
79 v_range: (f64, f64),
80 resolution: (u32, u32),
81 ) -> Self {
82 let (nu, nv) = resolution;
83 assert!(nu >= 2 && nv >= 2, "resolution must be >= (2, 2)");
84
85 let mut points = Vec::with_capacity((nu * nv) as usize);
86 for i in 0..nu {
87 let u = u_range.0 + (u_range.1 - u_range.0) * (i as f64 / (nu - 1) as f64);
88 for j in 0..nv {
89 let v = v_range.0 + (v_range.1 - v_range.0) * (j as f64 / (nv - 1) as f64);
90 points.push(uv_func(u, v));
91 }
92 }
93
94 let triangle_indices = generate_grid_indices(nu, nv);
95
96 let vertex_colors = vec![color::palette::css::BLUE.with_alpha(1.0); points.len()];
97 let vertex_normals = vec![DVec3::ZERO; points.len()];
98 Self {
99 vertices: points,
100 triangle_indices,
101 resolution,
102 vertex_colors,
103 vertex_normals,
104 }
105 }
106
107 pub fn with_vertex_colors(mut self, colors: Vec<AlphaColor<Srgb>>) -> Self {
109 self.vertex_colors = colors;
110 self
111 }
112
113 pub fn with_fill_by_z(mut self, colorscale: &[(AlphaColor<Srgb>, f64)]) -> Self {
118 let colors = self
119 .vertices
120 .iter()
121 .map(|p| colorscale_lookup(colorscale, p.z))
122 .collect();
123 self.vertex_colors = colors;
124 self
125 }
126
127 pub fn with_smooth_normals(mut self) -> Self {
129 self.update_smooth_normals();
130 self
131 }
132 pub fn update_smooth_normals(&mut self) -> &mut Self {
134 self.vertex_normals = compute_smooth_normals(&self.vertices, &self.triangle_indices);
135 self
136 }
137}
138
139impl Interpolatable for Surface {
140 fn lerp(&self, target: &Self, t: f64) -> Self {
141 Self {
142 vertices: self.vertices.lerp(&target.vertices, t),
143 triangle_indices: if t < 0.5 {
145 self.triangle_indices.clone()
146 } else {
147 target.triangle_indices.clone()
148 },
149 resolution: if t < 0.5 {
150 self.resolution
151 } else {
152 target.resolution
153 },
154 vertex_colors: self.vertex_colors.lerp(&target.vertex_colors, t),
155 vertex_normals: self.vertex_normals.lerp(&target.vertex_normals, t),
156 }
157 }
158}
159
160impl FillColor for Surface {
161 fn fill_color(&self) -> AlphaColor<Srgb> {
162 let Rgba(rgba) = self
164 .vertex_colors
165 .first()
166 .cloned()
167 .map(Rgba::from)
168 .unwrap_or_default();
169 AlphaColor::new([rgba.x, rgba.y, rgba.z, rgba.w])
170 }
171
172 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
173 self.vertex_colors.fill(color);
174 self
175 }
176
177 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
178 self.vertex_colors
179 .iter_mut()
180 .for_each(|x| *x = x.with_alpha(opacity));
181 self
182 }
183}
184
185impl Opacity for Surface {
186 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
187 self.set_fill_opacity(opacity)
188 }
189}
190
191impl From<Surface> for MeshItem {
192 fn from(value: Surface) -> Self {
193 MeshItem {
194 points: value.vertices.into(),
195 triangle_indices: value.triangle_indices,
196 vertex_colors: value
197 .vertex_colors
198 .into_iter()
199 .map(Rgba::from)
200 .collect::<Vec<_>>()
201 .into(),
202 vertex_normals: value.vertex_normals.into(),
203 }
204 }
205}
206
207impl Extract for Surface {
208 type Target = CoreItem;
209 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
210 MeshItem::from(self.clone()).extract_into(buf);
211 }
212}
213
214impl<G: Into<ranim_core::glam::DAffine3>> ApplyTransform<G> for Surface {
215 fn apply(&mut self, transform: G) -> &mut Self {
216 let transform = transform.into();
217 self.vertices.apply(transform);
218 if transform.matrix3.determinant().abs() > 1e-12 {
219 let normal_matrix = transform.matrix3.inverse().transpose();
220 self.vertex_normals.iter_mut().for_each(|normal| {
221 if let Some(unit) = (normal_matrix * *normal).try_normalize() {
222 *normal = unit;
223 }
224 });
225 }
226 self
227 }
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233 use ranim_core::glam::dvec3;
234
235 #[test]
236 fn test_flat_surface() {
237 let surface =
238 Surface::from_uv_func(|u, v| dvec3(u, v, 0.0), (0.0, 1.0), (0.0, 1.0), (3, 3));
239 assert_eq!(surface.vertices.len(), 9);
240 assert_eq!(surface.triangle_indices.len(), 24);
241 assert_eq!(surface.resolution, (3, 3));
242
243 assert_eq!(surface.vertices[0], dvec3(0.0, 0.0, 0.0));
245 assert_eq!(surface.vertices[2], dvec3(0.0, 1.0, 0.0));
246 assert_eq!(surface.vertices[6], dvec3(1.0, 0.0, 0.0));
247 assert_eq!(surface.vertices[8], dvec3(1.0, 1.0, 0.0));
248 }
249
250 #[test]
251 fn test_surface_extract() {
252 let surface =
253 Surface::from_uv_func(|u, v| dvec3(u, v, 0.0), (0.0, 1.0), (0.0, 1.0), (2, 2));
254 let items = surface.extract();
255 assert_eq!(items.len(), 1);
256 match &items[0] {
257 CoreItem::MeshItem(mesh) => {
258 assert_eq!(mesh.points.len(), 4);
259 assert_eq!(mesh.triangle_indices.len(), 6);
260 }
261 _ => panic!("expected MeshItem"),
262 }
263 }
264
265 #[test]
266 fn test_surface_interpolation() {
267 let a = Surface::from_uv_func(|u, v| dvec3(u, v, 0.0), (0.0, 1.0), (0.0, 1.0), (2, 2));
268 let b = Surface::from_uv_func(|u, v| dvec3(u, v, 1.0), (0.0, 1.0), (0.0, 1.0), (2, 2));
269 let mid = a.lerp(&b, 0.5);
270 for p in &mid.vertices {
272 assert!((p.z - 0.5).abs() < 1e-10);
273 }
274 }
275}