Skip to main content

gizmo_renderer/asset/
procedural.rs

1use crate::components::Mesh;
2use crate::renderer::Vertex;
3use gizmo_math::Vec3;
4use std::sync::Arc;
5use wgpu::util::DeviceExt;
6
7impl super::AssetManager {
8    pub fn create_tetrahedron(device: &wgpu::Device, size: f32) -> Mesh {
9        let s = size;
10        let p0 = [s, s, s];
11        let p1 = [-s, -s, s];
12        let p2 = [-s, s, -s];
13        let p3 = [s, -s, -s];
14
15        let mut vertices = Vec::new();
16        let faces = [
17            (p0, p1, p2),
18            (p0, p2, p3),
19            (p0, p3, p1),
20            (p1, p3, p2),
21        ];
22
23        let def_j = [0; 4];
24        let def_w = [0.0; 4];
25
26        for (a, b, c) in faces {
27            let va = Vec3::from_array(a);
28            let vb = Vec3::from_array(b);
29            let vc = Vec3::from_array(c);
30            let n = (vc - va).cross(vb - va).normalize();
31            let normal = [n.x, n.y, n.z];
32
33            vertices.push(Vertex { position: a, color: [1.0; 3], normal, tex_coords: [0.0, 0.0], joint_indices: def_j, joint_weights: def_w, ..Default::default() });
34            vertices.push(Vertex { position: b, color: [1.0; 3], normal, tex_coords: [1.0, 0.0], joint_indices: def_j, joint_weights: def_w, ..Default::default() });
35            vertices.push(Vertex { position: c, color: [1.0; 3], normal, tex_coords: [0.5, 1.0], joint_indices: def_j, joint_weights: def_w, ..Default::default() });
36        }
37
38        let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
39            label: Some("Tetrahedron VBuf"),
40            contents: bytemuck::cast_slice(&vertices),
41            usage: wgpu::BufferUsages::VERTEX,
42        });
43
44        Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, "tetrahedron".to_string())
45    }
46
47    pub fn create_conical_frustum(device: &wgpu::Device, radius_bottom: f32, radius_top: f32, height: f32, radial_segments: u32) -> Mesh {
48        let radial_segments = radial_segments.max(3);
49        let mut vertices = Vec::new();
50        let pi = std::f32::consts::PI;
51        let half_h = height / 2.0;
52
53        let def_j = [0; 4]; let def_w = [0.0; 4];
54        let col = [1.0; 3];
55
56        let y_normal = (radius_bottom - radius_top) / height;
57
58        for i in 0..radial_segments {
59            let t1 = (i as f32 / radial_segments as f32) * 2.0 * pi;
60            let t2 = ((i + 1) as f32 / radial_segments as f32) * 2.0 * pi;
61
62            let u1 = i as f32 / radial_segments as f32;
63            let u2 = (i + 1) as f32 / radial_segments as f32;
64
65            let p1_top = [radius_top * t1.cos(), half_h, radius_top * t1.sin()];
66            let p1_bot = [radius_bottom * t1.cos(), -half_h, radius_bottom * t1.sin()];
67            let p2_top = [radius_top * t2.cos(), half_h, radius_top * t2.sin()];
68            let p2_bot = [radius_bottom * t2.cos(), -half_h, radius_bottom * t2.sin()];
69
70            let n1 = Vec3::new(t1.cos(), y_normal, t1.sin()).normalize();
71            let n2 = Vec3::new(t2.cos(), y_normal, t2.sin()).normalize();
72            let n1_arr = [n1.x, n1.y, n1.z];
73            let n2_arr = [n2.x, n2.y, n2.z];
74
75            // Sides (CCW from outside)
76            vertices.push(Vertex { position: p1_top, normal: n1_arr, tex_coords: [u1, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
77            vertices.push(Vertex { position: p1_bot, normal: n1_arr, tex_coords: [u1, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
78            vertices.push(Vertex { position: p2_bot, normal: n2_arr, tex_coords: [u2, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
79
80            vertices.push(Vertex { position: p1_top, normal: n1_arr, tex_coords: [u1, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
81            vertices.push(Vertex { position: p2_bot, normal: n2_arr, tex_coords: [u2, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
82            vertices.push(Vertex { position: p2_top, normal: n2_arr, tex_coords: [u2, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
83
84            // Top Cap (CCW from above)
85            vertices.push(Vertex { position: [0.0, half_h, 0.0], normal: [0.0, 1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
86            vertices.push(Vertex { position: p1_top, normal: [0.0, 1.0, 0.0], tex_coords: [0.5 + 0.5 * t1.cos(), 0.5 + 0.5 * t1.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
87            vertices.push(Vertex { position: p2_top, normal: [0.0, 1.0, 0.0], tex_coords: [0.5 + 0.5 * t2.cos(), 0.5 + 0.5 * t2.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
88
89            // Bottom Cap (CCW from below)
90            vertices.push(Vertex { position: [0.0, -half_h, 0.0], normal: [0.0, -1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
91            vertices.push(Vertex { position: p2_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + 0.5 * t2.cos(), 0.5 + 0.5 * t2.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
92            vertices.push(Vertex { position: p1_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + 0.5 * t1.cos(), 0.5 + 0.5 * t1.sin()], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
93        }
94
95        let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
96            label: Some("Conical Frustum VBuf"),
97            contents: bytemuck::cast_slice(&vertices),
98            usage: wgpu::BufferUsages::VERTEX,
99        });
100
101        Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, "conical_frustum".to_string())
102    }
103
104    pub fn create_convex_extrusion(device: &wgpu::Device, points_2d: &[[f32; 2]], depth: f32) -> Mesh {
105        let mut vertices = Vec::new();
106        let half_d = depth / 2.0;
107        let def_j = [0; 4]; let def_w = [0.0; 4];
108        let col = [1.0; 3];
109
110        let count = points_2d.len();
111        
112        let mut cx = 0.0;
113        let mut cy = 0.0;
114        for p in points_2d {
115            cx += p[0];
116            cy += p[1];
117        }
118        cx /= count as f32;
119        cy /= count as f32;
120
121        for i in 0..count {
122            let p1 = points_2d[i];
123            let p2 = points_2d[(i + 1) % count];
124
125            let dx = p2[0] - p1[0];
126            let dy = p2[1] - p1[1];
127            let len = (dx*dx + dy*dy).sqrt();
128            let nx = dy / len;
129            let ny = -dx / len;
130            let normal = [nx, 0.0, ny];
131
132            let v1_top = [p1[0], half_d, p1[1]];
133            let v1_bot = [p1[0], -half_d, p1[1]];
134            let v2_top = [p2[0], half_d, p2[1]];
135            let v2_bot = [p2[0], -half_d, p2[1]];
136
137            // Side (CCW from outside)
138            vertices.push(Vertex { position: v1_top, normal, tex_coords: [0.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
139            vertices.push(Vertex { position: v1_bot, normal, tex_coords: [0.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
140            vertices.push(Vertex { position: v2_bot, normal, tex_coords: [1.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
141
142            vertices.push(Vertex { position: v1_top, normal, tex_coords: [0.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
143            vertices.push(Vertex { position: v2_bot, normal, tex_coords: [1.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
144            vertices.push(Vertex { position: v2_top, normal, tex_coords: [1.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
145
146            // Top Cap (Triangulate via center, CCW from above)
147            vertices.push(Vertex { position: [cx, half_d, cy], normal: [0.0, 1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
148            vertices.push(Vertex { position: v1_top, normal: [0.0, 1.0, 0.0], tex_coords: [0.5 + p1[0], 0.5 + p1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
149            vertices.push(Vertex { position: v2_top, normal: [0.0, 1.0, 0.0], tex_coords: [0.5 + p2[0], 0.5 + p2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
150
151            // Bottom Cap (CCW from below)
152            vertices.push(Vertex { position: [cx, -half_d, cy], normal: [0.0, -1.0, 0.0], tex_coords: [0.5, 0.5], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
153            vertices.push(Vertex { position: v2_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + p2[0], 0.5 + p2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
154            vertices.push(Vertex { position: v1_bot, normal: [0.0, -1.0, 0.0], tex_coords: [0.5 + p1[0], 0.5 + p1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
155        }
156
157        let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
158            label: Some("Extrusion VBuf"),
159            contents: bytemuck::cast_slice(&vertices),
160            usage: wgpu::BufferUsages::VERTEX,
161        });
162
163        Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, "extrusion".to_string())
164    }
165
166    pub fn create_ring_extrusion(device: &wgpu::Device, inner_points: &[[f32; 2]], outer_points: &[[f32; 2]], depth: f32) -> Mesh {
167        let mut vertices = Vec::new();
168        let half_d = depth / 2.0;
169        let def_j = [0; 4]; let def_w = [0.0; 4];
170        let col = [1.0; 3];
171
172        let count = outer_points.len();
173
174        for i in 0..count {
175            let o1 = outer_points[i];
176            let o2 = outer_points[(i + 1) % count];
177            let i1 = inner_points[i];
178            let i2 = inner_points[(i + 1) % count];
179
180            // Outer side normal
181            let dx_o = o2[0] - o1[0]; let dy_o = o2[1] - o1[1];
182            let len_o = (dx_o*dx_o + dy_o*dy_o).sqrt();
183            let nx_o = dy_o / len_o; let ny_o = -dx_o / len_o;
184            let normal_o = [nx_o, 0.0, ny_o];
185
186            // Inner side normal (flipped)
187            let dx_i = i2[0] - i1[0]; let dy_i = i2[1] - i1[1];
188            let len_i = (dx_i*dx_i + dy_i*dy_i).sqrt();
189            let nx_i = -dy_i / len_i; let ny_i = dx_i / len_i;
190            let normal_i = [nx_i, 0.0, ny_i];
191
192            let v_o1_t = [o1[0], half_d, o1[1]]; let v_o1_b = [o1[0], -half_d, o1[1]];
193            let v_o2_t = [o2[0], half_d, o2[1]]; let v_o2_b = [o2[0], -half_d, o2[1]];
194            
195            let v_i1_t = [i1[0], half_d, i1[1]]; let v_i1_b = [i1[0], -half_d, i1[1]];
196            let v_i2_t = [i2[0], half_d, i2[1]]; let v_i2_b = [i2[0], -half_d, i2[1]];
197
198            // Outer Side (CCW from outside)
199            vertices.push(Vertex { position: v_o1_t, normal: normal_o, tex_coords: [0.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
200            vertices.push(Vertex { position: v_o1_b, normal: normal_o, tex_coords: [0.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
201            vertices.push(Vertex { position: v_o2_b, normal: normal_o, tex_coords: [1.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
202            
203            vertices.push(Vertex { position: v_o1_t, normal: normal_o, tex_coords: [0.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
204            vertices.push(Vertex { position: v_o2_b, normal: normal_o, tex_coords: [1.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
205            vertices.push(Vertex { position: v_o2_t, normal: normal_o, tex_coords: [1.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
206
207            // Inner Side (CCW from outside)
208            vertices.push(Vertex { position: v_i2_t, normal: normal_i, tex_coords: [0.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
209            vertices.push(Vertex { position: v_i2_b, normal: normal_i, tex_coords: [0.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
210            vertices.push(Vertex { position: v_i1_b, normal: normal_i, tex_coords: [1.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
211            
212            vertices.push(Vertex { position: v_i2_t, normal: normal_i, tex_coords: [0.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
213            vertices.push(Vertex { position: v_i1_b, normal: normal_i, tex_coords: [1.0, 1.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
214            vertices.push(Vertex { position: v_i1_t, normal: normal_i, tex_coords: [1.0, 0.0], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
215
216            // Top Cap Quad (o1, o2, i1, i2 - CCW from above)
217            let n_top = [0.0, 1.0, 0.0];
218            vertices.push(Vertex { position: v_o1_t, normal: n_top, tex_coords: [o1[0], o1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
219            vertices.push(Vertex { position: v_i1_t, normal: n_top, tex_coords: [i1[0], i1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
220            vertices.push(Vertex { position: v_o2_t, normal: n_top, tex_coords: [o2[0], o2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
221            
222            vertices.push(Vertex { position: v_o2_t, normal: n_top, tex_coords: [o2[0], o2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
223            vertices.push(Vertex { position: v_i1_t, normal: n_top, tex_coords: [i1[0], i1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
224            vertices.push(Vertex { position: v_i2_t, normal: n_top, tex_coords: [i2[0], i2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
225
226            // Bottom Cap Quad (o1, o2, i1, i2 - CCW from below)
227            let n_bot = [0.0, -1.0, 0.0];
228            vertices.push(Vertex { position: v_o1_b, normal: n_bot, tex_coords: [o1[0], o1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
229            vertices.push(Vertex { position: v_o2_b, normal: n_bot, tex_coords: [o2[0], o2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
230            vertices.push(Vertex { position: v_i1_b, normal: n_bot, tex_coords: [i1[0], i1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
231            
232            vertices.push(Vertex { position: v_o2_b, normal: n_bot, tex_coords: [o2[0], o2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
233            vertices.push(Vertex { position: v_i2_b, normal: n_bot, tex_coords: [i2[0], i2[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
234            vertices.push(Vertex { position: v_i1_b, normal: n_bot, tex_coords: [i1[0], i1[1]], color: col, joint_indices: def_j, joint_weights: def_w, ..Default::default() });
235        }
236
237        let vbuf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
238            label: Some("Ring Extrusion VBuf"),
239            contents: bytemuck::cast_slice(&vertices),
240            usage: wgpu::BufferUsages::VERTEX,
241        });
242
243        Mesh::new(device, Arc::new(vbuf), &vertices, Vec3::ZERO, "ring_extrusion".to_string())
244    }
245}