1use ranim_core::{
4 Extract,
5 color::{self, AlphaColor, Srgb},
6 components::rgba::Rgba,
7 core_item::CoreItem,
8 glam::{DMat4, DVec3},
9 traits::{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)]
53pub struct Surface {
54 pub vertices: Vec<DVec3>,
56 pub vertex_colors: Vec<AlphaColor<Srgb>>,
58 pub vertex_normals: Vec<DVec3>,
60 pub triangle_indices: Vec<u32>,
62 pub resolution: (u32, u32),
64 pub transform: DMat4,
66}
67
68impl Surface {
69 pub fn from_uv_func(
74 uv_func: impl Fn(f64, f64) -> DVec3,
75 u_range: (f64, f64),
76 v_range: (f64, f64),
77 resolution: (u32, u32),
78 ) -> Self {
79 let (nu, nv) = resolution;
80 assert!(nu >= 2 && nv >= 2, "resolution must be >= (2, 2)");
81
82 let mut points = Vec::with_capacity((nu * nv) as usize);
83 for i in 0..nu {
84 let u = u_range.0 + (u_range.1 - u_range.0) * (i as f64 / (nu - 1) as f64);
85 for j in 0..nv {
86 let v = v_range.0 + (v_range.1 - v_range.0) * (j as f64 / (nv - 1) as f64);
87 points.push(uv_func(u, v));
88 }
89 }
90
91 let triangle_indices = generate_grid_indices(nu, nv);
92
93 let vertex_colors = vec![color::palette::css::BLUE.with_alpha(1.0); points.len()];
94 let vertex_normals = vec![DVec3::ZERO; points.len()];
95 Self {
96 vertices: points,
97 triangle_indices,
98 resolution,
99 vertex_colors,
100 vertex_normals,
101 transform: DMat4::IDENTITY,
102 }
103 }
104
105 pub fn with_vertex_colors(mut self, colors: Vec<AlphaColor<Srgb>>) -> Self {
107 self.vertex_colors = colors;
108 self
109 }
110
111 pub fn with_fill_by_z(mut self, colorscale: &[(AlphaColor<Srgb>, f64)]) -> Self {
116 let colors = self
117 .vertices
118 .iter()
119 .map(|p| colorscale_lookup(colorscale, p.z))
120 .collect();
121 self.vertex_colors = colors;
122 self
123 }
124
125 pub fn with_transform(mut self, transform: DMat4) -> Self {
127 self.transform = transform;
128 self
129 }
130
131 pub fn with_smooth_normals(mut self) -> Self {
133 self.update_smooth_normals();
134 self
135 }
136 pub fn update_smooth_normals(&mut self) -> &mut Self {
138 self.vertex_normals = compute_smooth_normals(&self.vertices, &self.triangle_indices);
139 self
140 }
141}
142
143impl Interpolatable for Surface {
144 fn lerp(&self, target: &Self, t: f64) -> Self {
145 Self {
146 vertices: self.vertices.lerp(&target.vertices, t),
147 triangle_indices: if t < 0.5 {
149 self.triangle_indices.clone()
150 } else {
151 target.triangle_indices.clone()
152 },
153 resolution: if t < 0.5 {
154 self.resolution
155 } else {
156 target.resolution
157 },
158 vertex_colors: self.vertex_colors.lerp(&target.vertex_colors, t),
159 vertex_normals: self.vertex_normals.lerp(&target.vertex_normals, t),
160 transform: Interpolatable::lerp(&self.transform, &target.transform, t),
161 }
162 }
163}
164
165impl FillColor for Surface {
166 fn fill_color(&self) -> AlphaColor<Srgb> {
167 let Rgba(rgba) = self
169 .vertex_colors
170 .first()
171 .cloned()
172 .map(Rgba::from)
173 .unwrap_or_default();
174 AlphaColor::new([rgba.x, rgba.y, rgba.z, rgba.w])
175 }
176
177 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
178 self.vertex_colors.fill(color);
179 self
180 }
181
182 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
183 self.vertex_colors
184 .iter_mut()
185 .for_each(|x| *x = x.with_alpha(opacity));
186 self
187 }
188}
189
190impl Opacity for Surface {
191 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
192 self.set_fill_opacity(opacity)
193 }
194}
195
196impl From<Surface> for MeshItem {
197 fn from(value: Surface) -> Self {
198 MeshItem {
199 points: value
200 .vertices
201 .iter()
202 .map(|p| p.as_vec3())
203 .collect::<Vec<_>>()
204 .into(),
205 triangle_indices: value.triangle_indices,
206 transform: value.transform.as_mat4(),
207 vertex_colors: value
208 .vertex_colors
209 .into_iter()
210 .map(Rgba::from)
211 .collect::<Vec<_>>()
212 .into(),
213 vertex_normals: value
214 .vertex_normals
215 .iter()
216 .map(|n| n.as_vec3())
217 .collect::<Vec<_>>()
218 .into(),
219 }
220 }
221}
222
223impl Extract for Surface {
224 type Target = CoreItem;
225 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
226 MeshItem::from(self.clone()).extract_into(buf);
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}