1use std::collections::HashSet;
16use std::f32::consts::PI;
17use super::GfxState;
18
19#[derive(Default, Clone)]
21pub struct Mesh {
22 pub verts: Vec<[f32; 3]>,
23 pub tris: Vec<[u32; 3]>,
24 pub edges: Vec<[u32; 2]>,
25 pub normals: Vec<[f32; 3]>,
28}
29
30impl Mesh {
31 fn v(&mut self, x: f32, y: f32, z: f32) -> u32 {
32 let i = self.verts.len() as u32;
33 self.verts.push([x, y, z]);
34 i
35 }
36 fn tri(&mut self, a: u32, b: u32, c: u32) { self.tris.push([a, b, c]); }
37 fn edge(&mut self, a: u32, b: u32) { self.edges.push([a, b]); }
38
39 fn face(&mut self, idx: &[u32]) {
41 for k in 1..idx.len() - 1 {
42 self.tris.push([idx[0], idx[k], idx[k + 1]]);
43 }
44 for k in 0..idx.len() {
45 self.edges.push([idx[k], idx[(k + 1) % idx.len()]]);
46 }
47 }
48
49 fn edges_from_tris(&mut self) {
51 let mut seen: HashSet<(u32, u32)> = HashSet::new();
52 for t in &self.tris {
53 for &(a, b) in &[(t[0], t[1]), (t[1], t[2]), (t[2], t[0])] {
54 let k = if a < b { (a, b) } else { (b, a) };
55 if seen.insert(k) { self.edges.push([k.0, k.1]); }
56 }
57 }
58 }
59
60 fn compute_smooth_normals(&mut self) {
64 let mut n = vec![[0.0f32; 3]; self.verts.len()];
65 for t in &self.tris {
66 let a = self.verts[t[0] as usize];
67 let b = self.verts[t[1] as usize];
68 let c = self.verts[t[2] as usize];
69 let u = [b[0]-a[0], b[1]-a[1], b[2]-a[2]];
70 let v = [c[0]-a[0], c[1]-a[1], c[2]-a[2]];
71 let f = [u[1]*v[2]-u[2]*v[1], u[2]*v[0]-u[0]*v[2], u[0]*v[1]-u[1]*v[0]];
72 for &i in t { let i = i as usize; n[i][0]+=f[0]; n[i][1]+=f[1]; n[i][2]+=f[2]; }
73 }
74 for p in &mut n {
75 let l = (p[0]*p[0]+p[1]*p[1]+p[2]*p[2]).sqrt();
76 if l > 1e-8 { p[0]/=l; p[1]/=l; p[2]/=l; }
77 }
78 self.normals = n;
79 }
80
81 fn transform(&mut self, c: [f32; 9]) {
83 let (cx, cy, cz) = (c[0], c[1], c[2]);
84 let (sx, sy, sz) = (c[3], c[4], c[5]);
85 let (rx, ry, rz) = (c[6], c[7], c[8]);
86 let (srx, crx) = rx.sin_cos();
87 let (sry, cry) = ry.sin_cos();
88 let (srz, crz) = rz.sin_cos();
89 for p in &mut self.verts {
90 let mut x = p[0] * sx;
91 let mut y = p[1] * sy;
92 let mut z = p[2] * sz;
93 let (ny, nz) = (y * crx - z * srx, y * srx + z * crx); y = ny; z = nz;
95 let (nx, nz2) = (x * cry + z * sry, -x * sry + z * cry); x = nx; z = nz2;
97 let (nx2, ny2) = (x * crz - y * srz, x * srz + y * crz); x = nx2; y = ny2;
99 *p = [x + cx, y + cy, z + cz];
100 }
101 }
102}
103
104#[inline] fn iarg(v: f32, default: i32) -> i32 { if v > 0.5 { v.round() as i32 } else { default } }
106#[inline] fn farg(v: f32, default: f32) -> f32 { if v > 1e-6 { v } else { default } }
107
108fn cube() -> Mesh {
111 let mut m = Mesh::default();
112 let s = 1.0;
113 let p = [
114 m.v(-s,-s,-s), m.v(s,-s,-s), m.v(s,s,-s), m.v(-s,s,-s), m.v(-s,-s, s), m.v(s,-s, s), m.v(s,s, s), m.v(-s,s, s), ];
117 m.face(&[p[0],p[1],p[2],p[3]]); m.face(&[p[5],p[4],p[7],p[6]]); m.face(&[p[4],p[0],p[3],p[7]]); m.face(&[p[1],p[5],p[6],p[2]]); m.face(&[p[4],p[5],p[1],p[0]]); m.face(&[p[3],p[2],p[6],p[7]]); m
124}
125
126fn tetrahedron() -> Mesh {
127 let mut m = Mesh::default();
128 let a = 1.0;
129 let p = [
130 m.v( a, a, a), m.v( a,-a,-a), m.v(-a, a,-a), m.v(-a,-a, a),
131 ];
132 m.face(&[p[0],p[1],p[2]]);
133 m.face(&[p[0],p[3],p[1]]);
134 m.face(&[p[0],p[2],p[3]]);
135 m.face(&[p[1],p[3],p[2]]);
136 m
137}
138
139fn octahedron() -> Mesh {
140 let mut m = Mesh::default();
141 let p = [
142 m.v( 1.0,0.0,0.0), m.v(-1.0,0.0,0.0),
143 m.v(0.0, 1.0,0.0), m.v(0.0,-1.0,0.0),
144 m.v(0.0,0.0, 1.0), m.v(0.0,0.0,-1.0),
145 ];
146 m.face(&[p[0],p[2],p[4]]); m.face(&[p[2],p[1],p[4]]);
147 m.face(&[p[1],p[3],p[4]]); m.face(&[p[3],p[0],p[4]]);
148 m.face(&[p[2],p[0],p[5]]); m.face(&[p[1],p[2],p[5]]);
149 m.face(&[p[3],p[1],p[5]]); m.face(&[p[0],p[3],p[5]]);
150 m
151}
152
153fn icosahedron_raw() -> Mesh {
154 let mut m = Mesh::default();
155 let t = (1.0 + 5.0_f32.sqrt()) / 2.0;
156 let s = 1.0 / (1.0 + t*t).sqrt(); let vs = [
158 [-1., t, 0.],[1., t, 0.],[-1.,-t, 0.],[1.,-t, 0.],
159 [0.,-1., t],[0., 1., t],[0.,-1.,-t],[0., 1.,-t],
160 [ t, 0.,-1.],[ t, 0., 1.],[-t, 0.,-1.],[-t, 0., 1.],
161 ];
162 for v in vs { m.v(v[0]*s, v[1]*s, v[2]*s); }
163 let f = [
164 [0,11,5],[0,5,1],[0,1,7],[0,7,10],[0,10,11],
165 [1,5,9],[5,11,4],[11,10,2],[10,7,6],[7,1,8],
166 [3,9,4],[3,4,2],[3,2,6],[3,6,8],[3,8,9],
167 [4,9,5],[2,4,11],[6,2,10],[8,6,7],[9,8,1],
168 ];
169 for t in f { m.tri(t[0],t[1],t[2]); }
170 m
171}
172
173fn icosahedron() -> Mesh { let mut m = icosahedron_raw(); m.edges_from_tris(); m }
174
175fn icosphere(subdiv: i32) -> Mesh {
176 let mut m = icosahedron_raw();
177 let n = subdiv.clamp(0, 4);
178 for _ in 0..n {
179 let mut nm = Mesh::default();
180 let mut mid: std::collections::HashMap<(u32,u32),u32> = std::collections::HashMap::new();
181 for v in &m.verts { nm.verts.push(*v); }
182 let mut midpoint = |nm: &mut Mesh, a: u32, b: u32, mid: &mut std::collections::HashMap<(u32,u32),u32>| -> u32 {
183 let key = if a < b { (a,b) } else { (b,a) };
184 if let Some(&i) = mid.get(&key) { return i; }
185 let pa = nm.verts[a as usize]; let pb = nm.verts[b as usize];
186 let mut mp = [(pa[0]+pb[0])/2.0,(pa[1]+pb[1])/2.0,(pa[2]+pb[2])/2.0];
187 let l = (mp[0]*mp[0]+mp[1]*mp[1]+mp[2]*mp[2]).sqrt();
188 mp = [mp[0]/l, mp[1]/l, mp[2]/l];
189 let i = nm.verts.len() as u32; nm.verts.push(mp); mid.insert(key, i); i
190 };
191 for t in &m.tris {
192 let a = midpoint(&mut nm, t[0], t[1], &mut mid);
193 let b = midpoint(&mut nm, t[1], t[2], &mut mid);
194 let c = midpoint(&mut nm, t[2], t[0], &mut mid);
195 nm.tri(t[0],a,c); nm.tri(t[1],b,a); nm.tri(t[2],c,b); nm.tri(a,b,c);
196 }
197 m = nm;
198 }
199 m.edges_from_tris();
200 m
201}
202
203fn dodecahedron() -> Mesh {
204 let mut m = Mesh::default();
205 let phi = (1.0 + 5.0_f32.sqrt()) / 2.0;
206 let b = 1.0 / phi;
207 let c = phi;
208 let r = (3.0_f32).sqrt(); let s = 1.0 / r;
210 let vs = [
211 [ 1., 1., 1.],[ 1., 1.,-1.],[ 1.,-1., 1.],[ 1.,-1.,-1.],
212 [-1., 1., 1.],[-1., 1.,-1.],[-1.,-1., 1.],[-1.,-1.,-1.],
213 [0., b, c],[0., b,-c],[0.,-b, c],[0.,-b,-c],
214 [ b, c, 0.],[ b,-c, 0.],[-b, c, 0.],[-b,-c, 0.],
215 [ c, 0., b],[ c, 0.,-b],[-c, 0., b],[-c, 0.,-b],
216 ];
217 for v in vs { m.v(v[0]*s, v[1]*s, v[2]*s); }
218 let faces: [[u32;5];12] = [
219 [0,8,10,2,16],[0,16,17,1,12],[0,12,14,4,8],
220 [1,9,5,14,12],[1,17,3,11,9],[2,10,6,15,13],
221 [2,13,3,17,16],[3,13,15,7,11],[4,14,5,19,18],
222 [4,18,6,10,8],[5,9,11,7,19],[6,18,19,7,15],
223 ];
224 for f in faces { m.face(&f); }
225 m
226}
227
228fn uv_sphere(seg: i32, rings: i32) -> Mesh {
231 let mut m = Mesh::default();
232 let seg = seg.clamp(3, 128);
233 let rings = rings.clamp(2, 128);
234 for r in 0..=rings {
235 let v = r as f32 / rings as f32;
236 let theta = v * PI; let (st, ct) = theta.sin_cos();
238 for s in 0..=seg {
239 let u = s as f32 / seg as f32;
240 let phi = u * 2.0 * PI;
241 let (sp, cp) = phi.sin_cos();
242 m.v(st * cp, ct, st * sp);
243 }
244 }
245 let stride = seg + 1;
246 for r in 0..rings {
247 for s in 0..seg {
248 let a = (r * stride + s) as u32;
249 let b = (r * stride + s + 1) as u32;
250 let cc = ((r + 1) * stride + s) as u32;
251 let d = ((r + 1) * stride + s + 1) as u32;
252 m.tri(a, cc, b); m.tri(b, cc, d);
253 }
254 }
255 m.edges_from_tris();
256 m
257}
258
259fn dome(seg: i32, rings: i32) -> Mesh {
260 let mut m = Mesh::default();
262 let seg = seg.clamp(3, 128);
263 let rings = rings.clamp(1, 128);
264 for r in 0..=rings {
265 let v = r as f32 / rings as f32;
266 let theta = v * (PI / 2.0); let (st, ct) = theta.sin_cos();
268 for s in 0..=seg {
269 let phi = s as f32 / seg as f32 * 2.0 * PI;
270 let (sp, cp) = phi.sin_cos();
271 m.v(st * cp, ct, st * sp);
272 }
273 }
274 let stride = seg + 1;
275 for r in 0..rings {
276 for s in 0..seg {
277 let a = (r*stride+s) as u32; let b=(r*stride+s+1) as u32;
278 let cc=((r+1)*stride+s) as u32; let d=((r+1)*stride+s+1) as u32;
279 m.tri(a, cc, b); m.tri(b, cc, d);
280 }
281 }
282 let centre = m.v(0.0, 0.0, 0.0);
284 for s in 0..seg {
285 let a = ((rings)*stride+s) as u32; let b=((rings)*stride+s+1) as u32;
286 m.tri(centre, b, a);
287 }
288 m.edges_from_tris();
289 m
290}
291
292fn cylinder(seg: i32) -> Mesh {
293 let mut m = Mesh::default();
294 let seg = seg.clamp(3, 256);
295 for s in 0..seg {
297 let phi = s as f32 / seg as f32 * 2.0 * PI;
298 let (sp, cp) = phi.sin_cos();
299 m.v(cp, -1.0, sp);
300 m.v(cp, 1.0, sp);
301 }
302 for s in 0..seg {
303 let b0 = (2*s) as u32; let t0 = (2*s+1) as u32;
304 let b1 = (2*((s+1)%seg)) as u32; let t1 = (2*((s+1)%seg)+1) as u32;
305 m.tri(b0, t0, b1); m.tri(b1, t0, t1);
306 m.edge(b0, b1); m.edge(t0, t1); m.edge(b0, t0);
307 }
308 let cb = m.v(0.0,-1.0,0.0); let ct = m.v(0.0,1.0,0.0);
309 for s in 0..seg {
310 let b0=(2*s) as u32; let b1=(2*((s+1)%seg)) as u32;
311 let t0=(2*s+1) as u32; let t1=(2*((s+1)%seg)+1) as u32;
312 m.tri(cb, b1, b0); m.tri(ct, t0, t1);
313 }
314 m
315}
316
317fn cone(seg: i32) -> Mesh {
318 let mut m = Mesh::default();
319 let seg = seg.clamp(3, 256);
320 let apex = m.v(0.0, 1.0, 0.0);
321 let base0 = m.verts.len() as u32;
322 for s in 0..seg {
323 let phi = s as f32 / seg as f32 * 2.0 * PI;
324 let (sp, cp) = phi.sin_cos();
325 m.v(cp, -1.0, sp);
326 }
327 let centre = m.v(0.0, -1.0, 0.0);
328 for s in 0..seg {
329 let a = base0 + s as u32; let b = base0 + ((s+1)%seg) as u32;
330 m.tri(apex, a, b); m.tri(centre, b, a); m.edge(a, b); m.edge(apex, a);
333 }
334 m
335}
336
337fn capsule(seg: i32, rings: i32) -> Mesh {
338 let mut m = Mesh::default();
340 let seg = seg.clamp(3, 128);
341 let rings = rings.clamp(1, 64);
342 let stride = seg + 1;
343 let mut ring_start = Vec::new();
345 let total_rows = 2 * rings; for row in 0..=total_rows {
347 ring_start.push(m.verts.len() as u32);
348 let (cy_off, theta) = if row <= rings {
349 let v = row as f32 / rings as f32;
351 (1.0, v * PI / 2.0)
352 } else {
353 let v = (row - rings) as f32 / rings as f32;
355 (-1.0, PI / 2.0 + v * PI / 2.0)
356 };
357 let (st, ct) = theta.sin_cos();
358 for s in 0..=seg {
359 let phi = s as f32 / seg as f32 * 2.0 * PI;
360 let (sp, cp) = phi.sin_cos();
361 m.v(st * cp, cy_off + ct, st * sp);
362 }
363 }
364 for row in 0..total_rows as usize {
365 for s in 0..seg {
366 let a = ring_start[row] + s as u32;
367 let b = ring_start[row] + s as u32 + 1;
368 let c = ring_start[row + 1] + s as u32;
369 let d = ring_start[row + 1] + s as u32 + 1;
370 m.tri(a, c, b); m.tri(b, c, d);
371 }
372 }
373 let _ = stride;
374 m.edges_from_tris();
375 m
376}
377
378fn torus(seg: i32, sides: i32, tube: f32) -> Mesh {
379 let mut m = Mesh::default();
380 let seg = seg.clamp(3, 256); let sides = sides.clamp(3, 128); let tube = tube.clamp(0.02, 0.9);
383 for i in 0..seg {
384 let u = i as f32 / seg as f32 * 2.0 * PI;
385 let (su, cu) = u.sin_cos();
386 for j in 0..sides {
387 let v = j as f32 / sides as f32 * 2.0 * PI;
388 let (sv, cv) = v.sin_cos();
389 let r = 1.0 - tube + tube * cv;
390 m.v(r * cu, tube * sv, r * su);
391 }
392 }
393 for i in 0..seg {
394 for j in 0..sides {
395 let a = (i*sides + j) as u32;
396 let b = (i*sides + (j+1)%sides) as u32;
397 let c = (((i+1)%seg)*sides + j) as u32;
398 let d = (((i+1)%seg)*sides + (j+1)%sides) as u32;
399 m.tri(a, c, b); m.tri(b, c, d);
400 }
401 }
402 m.edges_from_tris();
403 m
404}
405
406fn pyramid(sides: i32) -> Mesh {
409 let mut m = Mesh::default();
410 let sides = sides.clamp(3, 128);
411 let apex = m.v(0.0, 1.0, 0.0);
412 let base0 = m.verts.len() as u32;
413 let mut ring = Vec::new();
414 for s in 0..sides {
415 let phi = s as f32 / sides as f32 * 2.0 * PI;
416 let (sp, cp) = phi.sin_cos();
417 ring.push(m.v(cp, -1.0, sp));
418 }
419 for s in 0..sides as usize {
420 let a = ring[s]; let b = ring[(s+1)%sides as usize];
421 m.tri(apex, a, b);
422 m.edge(a, b); m.edge(apex, a);
423 }
424 let mut rev: Vec<u32> = ring.clone(); rev.reverse();
426 for k in 1..rev.len()-1 { m.tri(rev[0], rev[k], rev[k+1]); }
427 let _ = base0;
428 m
429}
430
431fn prism(sides: i32) -> Mesh {
432 let mut m = Mesh::default();
433 let sides = sides.clamp(3, 128);
434 let mut bot = Vec::new(); let mut top = Vec::new();
435 for s in 0..sides {
436 let phi = s as f32 / sides as f32 * 2.0 * PI;
437 let (sp, cp) = phi.sin_cos();
438 bot.push(m.v(cp, -1.0, sp));
439 top.push(m.v(cp, 1.0, sp));
440 }
441 let n = sides as usize;
442 for s in 0..n {
443 let b0=bot[s]; let b1=bot[(s+1)%n]; let t0=top[s]; let t1=top[(s+1)%n];
444 m.tri(b0, t0, b1); m.tri(b1, t0, t1);
445 m.edge(b0,b1); m.edge(t0,t1); m.edge(b0,t0);
446 }
447 for k in 1..n-1 { m.tri(top[0], top[k], top[k+1]); }
448 let mut rb: Vec<u32> = bot.clone(); rb.reverse();
449 for k in 1..rb.len()-1 { m.tri(rb[0], rb[k], rb[k+1]); }
450 m
451}
452
453fn frustum(sides: i32, top_ratio: f32) -> Mesh {
454 let mut m = Mesh::default();
455 let sides = sides.clamp(3, 256);
456 let tr = top_ratio.clamp(0.0, 1.0);
457 let mut bot = Vec::new(); let mut top = Vec::new();
458 for s in 0..sides {
459 let phi = s as f32 / sides as f32 * 2.0 * PI;
460 let (sp, cp) = phi.sin_cos();
461 bot.push(m.v(cp, -1.0, sp));
462 top.push(m.v(cp*tr, 1.0, sp*tr));
463 }
464 let n = sides as usize;
465 for s in 0..n {
466 let b0=bot[s]; let b1=bot[(s+1)%n]; let t0=top[s]; let t1=top[(s+1)%n];
467 m.tri(b0, t0, b1); m.tri(b1, t0, t1);
468 m.edge(b0,b1); m.edge(t0,t1); m.edge(b0,t0);
469 }
470 if tr > 0.001 { for k in 1..n-1 { m.tri(top[0], top[k], top[k+1]); } }
471 let mut rb: Vec<u32> = bot.clone(); rb.reverse();
472 for k in 1..rb.len()-1 { m.tri(rb[0], rb[k], rb[k+1]); }
473 m
474}
475
476fn gear(teeth: i32, tooth: f32) -> Mesh {
479 let mut m = Mesh::default();
481 let teeth = teeth.clamp(3, 96);
482 let tooth = tooth.clamp(0.02, 0.6);
483 let pts = teeth * 4; let mut bot = Vec::new(); let mut top = Vec::new();
485 for i in 0..pts {
486 let phi = i as f32 / pts as f32 * 2.0 * PI;
487 let phase = (i % 4) as f32;
489 let r = if phase < 2.0 { 1.0 } else { 1.0 - tooth };
490 let (sp, cp) = phi.sin_cos();
491 bot.push(m.v(cp*r, -1.0, sp*r));
492 top.push(m.v(cp*r, 1.0, sp*r));
493 }
494 let n = pts as usize;
495 for s in 0..n {
496 let b0=bot[s]; let b1=bot[(s+1)%n]; let t0=top[s]; let t1=top[(s+1)%n];
497 m.tri(b0, t0, b1); m.tri(b1, t0, t1); m.edge(b0,b1); m.edge(t0,t1); m.edge(b0,t0);
499 }
500 let cb = m.v(0.0,-1.0,0.0); let ct = m.v(0.0,1.0,0.0);
501 for s in 0..n {
502 let b0=bot[s]; let b1=bot[(s+1)%n]; let t0=top[s]; let t1=top[(s+1)%n];
503 m.tri(cb, b1, b0); m.tri(ct, t0, t1); }
505 m
506}
507
508fn gyro(rings: i32) -> Mesh {
509 let mut m = Mesh::default();
511 let rings = rings.clamp(1, 6);
512 for k in 0..rings {
513 let scale = 1.0 - k as f32 * (0.8 / rings as f32);
514 let mut ring = torus(40, 8, 0.06 / scale.max(0.2));
515 let rot = match k % 3 {
517 0 => [0.0, 0.0, 0.0],
518 1 => [PI/2.0, 0.0, 0.0],
519 _ => [0.0, 0.0, PI/2.0],
520 };
521 ring.transform([0.0,0.0,0.0, scale,scale,scale, rot[0],rot[1],rot[2]]);
522 let base = m.verts.len() as u32;
523 for v in &ring.verts { m.verts.push(*v); }
524 for t in &ring.tris { m.tri(t[0]+base, t[1]+base, t[2]+base); }
525 for e in &ring.edges { m.edge(e[0]+base, e[1]+base); }
526 }
527 m
528}
529
530fn append_mesh(dst: &mut Mesh, src: &Mesh) {
533 let base = dst.verts.len() as u32;
534 for v in &src.verts { dst.verts.push(*v); }
535 for t in &src.tris { dst.tri(t[0]+base, t[1]+base, t[2]+base); }
536 for e in &src.edges { dst.edge(e[0]+base, e[1]+base); }
537}
538
539fn box_between(x0:f32,x1:f32,y0:f32,y1:f32,z0:f32,z1:f32) -> Mesh {
540 let mut m = Mesh::default();
541 let p=[
542 m.v(x0,y0,z0),m.v(x1,y0,z0),m.v(x1,y1,z0),m.v(x0,y1,z0),
543 m.v(x0,y0,z1),m.v(x1,y0,z1),m.v(x1,y1,z1),m.v(x0,y1,z1),
544 ];
545 m.face(&[p[0],p[1],p[2],p[3]]);
546 m.face(&[p[5],p[4],p[7],p[6]]);
547 m.face(&[p[4],p[0],p[3],p[7]]);
548 m.face(&[p[1],p[5],p[6],p[2]]);
549 m.face(&[p[4],p[5],p[1],p[0]]);
550 m.face(&[p[3],p[2],p[6],p[7]]);
551 m
552}
553
554fn helix(turns: i32, tube: f32, sides: i32) -> Mesh {
556 let mut m = Mesh::default();
557 let turns = turns.clamp(1, 24);
558 let sides = sides.clamp(3, 32);
559 let tube = tube.clamp(0.02, 0.5);
560 let seg_per = 24;
561 let total = turns * seg_per;
562 for i in 0..=total {
563 let ang = (i as f32 / seg_per as f32) * 2.0 * PI;
564 let y = -1.0 + 2.0 * (i as f32 / total as f32);
565 let cen = [ang.cos(), y, ang.sin()];
566 let radial = [ang.cos(), 0.0, ang.sin()];
567 let up = [0.0, 1.0, 0.0];
568 for j in 0..sides {
569 let v = j as f32 / sides as f32 * 2.0 * PI;
570 let (sv, cv) = v.sin_cos();
571 m.v(cen[0] + tube*(cv*radial[0] + sv*up[0]),
572 cen[1] + tube*(cv*radial[1] + sv*up[1]),
573 cen[2] + tube*(cv*radial[2] + sv*up[2]));
574 }
575 }
576 let s = sides;
577 for i in 0..total {
578 for j in 0..sides {
579 let a=(i*s+j) as u32; let b=(i*s+(j+1)%s) as u32;
580 let c=((i+1)*s+j) as u32; let d=((i+1)*s+(j+1)%s) as u32;
581 m.tri(a,c,b); m.tri(b,c,d);
582 }
583 }
584 m.edges_from_tris();
585 m
586}
587
588fn arch(segs: i32, tube: f32) -> Mesh {
590 let mut m = Mesh::default();
591 let segs = segs.clamp(6, 128);
592 let sides = 10i32;
593 let tube = tube.clamp(0.05, 0.4);
594 for i in 0..=segs {
595 let a = PI * (i as f32 / segs as f32); let cen = [a.cos(), a.sin(), 0.0];
597 let radial = [a.cos(), a.sin(), 0.0];
598 let binorm = [0.0, 0.0, 1.0];
599 for j in 0..sides {
600 let v = j as f32 / sides as f32 * 2.0 * PI;
601 let (sv, cv) = v.sin_cos();
602 m.v(cen[0] + tube*(cv*radial[0] + sv*binorm[0]),
603 cen[1] + tube*(cv*radial[1] + sv*binorm[1]),
604 cen[2] + tube*(cv*radial[2] + sv*binorm[2]));
605 }
606 }
607 for i in 0..segs {
608 for j in 0..sides {
609 let a=(i*sides+j) as u32; let b=(i*sides+(j+1)%sides) as u32;
610 let c=((i+1)*sides+j) as u32; let d=((i+1)*sides+(j+1)%sides) as u32;
611 m.tri(a,c,b); m.tri(b,c,d);
612 }
613 }
614 m.edges_from_tris();
615 m
616}
617
618fn stairs(steps: i32) -> Mesh {
620 let mut m = Mesh::default();
621 let steps = steps.clamp(2, 40);
622 let sh = 2.0 / steps as f32;
623 let sd = 2.0 / steps as f32;
624 for i in 0..steps {
625 let y0 = -1.0 + i as f32 * sh; let y1 = y0 + sh;
626 let z0 = -1.0 + i as f32 * sd; let zf = z0 + sd;
627 let blk = box_between(-1.0, 1.0, y0, y1, z0, zf);
628 append_mesh(&mut m, &blk);
629 }
630 m
631}
632
633fn star_prism(points: i32, inner: f32) -> Mesh {
635 let mut m = Mesh::default();
636 let points = points.clamp(3, 32);
637 let inner = inner.clamp(0.1, 0.95);
638 let n = (points * 2) as usize;
639 let mut bot = Vec::new(); let mut top = Vec::new();
640 for k in 0..n {
641 let ang = k as f32 / n as f32 * 2.0 * PI;
642 let r = if k % 2 == 0 { 1.0 } else { inner };
643 let (s, c) = ang.sin_cos();
644 bot.push(m.v(c*r, -1.0, s*r));
645 top.push(m.v(c*r, 1.0, s*r));
646 }
647 for k in 0..n {
648 let b0=bot[k]; let b1=bot[(k+1)%n]; let t0=top[k]; let t1=top[(k+1)%n];
649 m.tri(b0,t0,b1); m.tri(b1,t0,t1);
650 m.edge(b0,b1); m.edge(t0,t1); m.edge(b0,t0);
651 }
652 for k in 1..n-1 { m.tri(top[0], top[k], top[k+1]); }
653 let mut rb = bot.clone(); rb.reverse();
654 for k in 1..rb.len()-1 { m.tri(rb[0], rb[k], rb[k+1]); }
655 m
656}
657
658fn capsule_chain(count: i32) -> Mesh {
660 let mut m = Mesh::default();
661 let count = count.clamp(1, 12);
662 let step = 2.0 / count as f32;
663 for i in 0..count {
664 let mut c = capsule(12, 4);
665 let cx = -1.0 + (i as f32 + 0.5) * step;
666 c.transform([cx, 0.0, 0.0, step*0.5, step*0.5, step*0.5, 0.0, 0.0, PI/2.0]);
667 append_mesh(&mut m, &c);
668 }
669 m
670}
671
672fn mobius(segs: i32, width: f32) -> Mesh {
674 let mut m = Mesh::default();
675 let segs = segs.clamp(8, 240);
676 let w = width.clamp(0.05, 0.6);
677 for i in 0..=segs {
678 let u = i as f32 / segs as f32 * 2.0 * PI;
679 for &vv in &[-1.0f32, 1.0] {
680 let v = vv * w;
681 let x = (1.0 + v/2.0 * (u/2.0).cos()) * u.cos();
682 let y = v/2.0 * (u/2.0).sin();
683 let z = (1.0 + v/2.0 * (u/2.0).cos()) * u.sin();
684 m.v(x, y, z);
685 }
686 }
687 for i in 0..segs {
688 let a=(2*i) as u32; let b=(2*i+1) as u32; let c=(2*(i+1)) as u32; let d=(2*(i+1)+1) as u32;
689 m.tri(a,c,b); m.tri(b,c,d);
690 }
691 m.edges_from_tris();
692 m
693}
694
695pub fn canon(name: &str) -> Option<&'static str> {
698 Some(match name {
699 "cube" | "box" | "立方体" | "方块" | "箱" | "정육면체" | "상자"
701 | "ลูกบาศก์" | "กล่อง" => "cube",
702 "sphere" | "球体" | "球" | "구" | "ทรงกลม" => "sphere",
704 "icosphere" | "二十面球" | "アイコ球" | "아이코구체" | "ทรงกลมเหลี่ยม" => "icosphere",
706 "dome" | "穹顶" | "ドーム" | "돔" | "โดม" => "dome",
708 "cylinder" | "圆柱" | "円柱" | "원기둥" | "ทรงกระบอก" => "cylinder",
710 "cone" | "圆锥" | "円錐" | "원뿔" | "กรวย" => "cone",
712 "capsule" | "胶囊" | "カプセル" | "캡슐" | "แคปซูล" => "capsule",
714 "torus" | "ring" | "圆环" | "トーラス" | "토러스" | "ทอรัส" => "torus",
716 "pyramid" | "金字塔" | "ピラミッド" | "피라미드" | "พีระมิด" => "pyramid",
718 "prism" | "棱柱" | "角柱" | "각기둥" | "ปริซึม" => "prism",
720 "frustum" | "棱台" | "錐台" | "원뿔대" | "กรวยตัด" => "frustum",
722 "tetrahedron" | "d4" | "四面体" | "정사면체" | "ทรงสี่หน้า" => "tetrahedron",
724 "octahedron" | "d8" | "八面体" | "정팔면체" | "ทรงแปดหน้า" => "octahedron",
726 "dodecahedron" | "d12" | "十二面体" | "정십이면체" | "ทรงสิบสองหน้า" => "dodecahedron",
728 "icosahedron" | "d20" | "二十面体" | "정이십면체" | "ทรงยี่สิบหน้า" => "icosahedron",
730 "gear" | "cog" | "齿轮" | "歯車" | "톱니바퀴" | "เฟือง" => "gear",
732 "gyro" | "陀螺" | "ジャイロ" | "자이로" | "ไจโร" => "gyro",
734 "helix" | "螺旋线" | "らせん" | "나선" | "เกลียว" => "helix",
736 "spring" | "弹簧" | "ばね" | "스프링" | "สปริง" => "spring",
738 "arch" | "拱门" | "アーチ" | "아치" | "ซุ้มโค้ง" => "arch",
740 "stairs" | "楼梯" | "階段" | "계단" | "บันได" => "stairs",
742 "star_prism" | "star" | "星柱" | "星型柱" | "별기둥" | "แท่งดาว" => "star_prism",
744 "capsule_chain" | "chain" | "胶囊链" | "カプセル鎖" | "캡슐체인" | "โซ่แคปซูล" => "capsule_chain",
746 "mobius" | "莫比乌斯" | "メビウス" | "뫼비우스" | "เมอบีอุส" => "mobius",
748 _ => return None,
749 })
750}
751
752pub fn build(kind: &str, c: [f32; 9], e0: f32, e1: f32, e2: f32) -> Option<Mesh> {
755 let mut m = match kind {
756 "cube" | "box" => cube(),
757 "sphere" => uv_sphere(iarg(e0,16), iarg(e1,12)),
758 "icosphere" => icosphere(iarg(e0,1)),
759 "dome" => dome(iarg(e0,24), iarg(e1,8)),
760 "cylinder" => cylinder(iarg(e0,24)),
761 "cone" => cone(iarg(e0,24)),
762 "capsule" => capsule(iarg(e0,16), iarg(e1,6)),
763 "torus" | "ring" => torus(iarg(e0,32), iarg(e1,12), farg(e2,0.35)),
764 "pyramid" => pyramid(iarg(e0,4)),
765 "prism" => prism(iarg(e0,6)),
766 "frustum" => frustum(iarg(e0,24), farg(e1,0.5)),
767 "tetrahedron" | "d4" => { let mut t = tetrahedron(); t.edges = vec![]; t.edges_from_tris(); t }
768 "octahedron" | "d8" => { let mut t = octahedron(); t.edges = vec![]; t.edges_from_tris(); t }
769 "dodecahedron"| "d12" => dodecahedron(),
770 "icosahedron" | "d20" => icosahedron(),
771 "gear" | "cog" => gear(iarg(e0,12), farg(e1,0.25)),
772 "gyro" => gyro(iarg(e0,3)),
773 "helix" => helix(iarg(e0,3), farg(e1,0.15), iarg(e2,8)),
774 "spring" => helix(iarg(e0,6), farg(e1,0.12), iarg(e2,8)),
775 "arch" => arch(iarg(e0,24), farg(e1,0.18)),
776 "stairs" => stairs(iarg(e0,5)),
777 "star_prism" => star_prism(iarg(e0,5), farg(e1,0.5)),
778 "capsule_chain" => capsule_chain(iarg(e0,3)),
779 "mobius" => mobius(iarg(e0,60), farg(e1,0.3)),
780 _ => return None,
781 };
782 m.transform(c);
783 m.compute_smooth_normals();
784 Some(m)
785}
786
787impl GfxState {
788 pub fn emit_mesh(&mut self, m: &Mesh, mode: i32) {
791 let near = -self.camera.zdist + 0.05;
792
793 let want_fill = mode == 0 || mode == 2;
794 if want_fill {
795 let have_normals = m.normals.len() == m.verts.len() && self.shade_mode != 0;
796 if have_normals {
797 let base = ling_graphics::shading::unpack(self.color);
801 let eye = [self.camera.tx, self.camera.ty, self.camera.tz];
802 let lights: Vec<ling_graphics::shading::LightS> = self.lights.iter().map(|l| {
803 ling_graphics::shading::LightS { pos:[l.x,l.y,l.z], color:[l.r,l.g,l.b], intensity:l.intensity, radius:l.radius }
804 }).collect();
805 let mut sp = self.shade;
806 sp.ambient = self.ambient; if self.shade_mode == 1 { sp.holo = false; sp.rim *= 0.4; }
808 let bands = sp.bands;
809 for t in &m.tris {
810 let ia=t[0] as usize; let ib=t[1] as usize; let ic=t[2] as usize;
811 let a=m.verts[ia]; let b=m.verts[ib]; let c=m.verts[ic];
812 let da=self.camera.depth(a[0],a[1],a[2]);
813 let db=self.camera.depth(b[0],b[1],b[2]);
814 let dc=self.camera.depth(c[0],c[1],c[2]);
815 if da<=near || db<=near || dc<=near { continue; }
816 let ca = ling_graphics::shading::pack(ling_graphics::shading::lit_vertex(base, m.normals[ia], a, eye, &lights, &sp));
817 let cb = ling_graphics::shading::pack(ling_graphics::shading::lit_vertex(base, m.normals[ib], b, eye, &lights, &sp));
818 let cc = ling_graphics::shading::pack(ling_graphics::shading::lit_vertex(base, m.normals[ic], c, eye, &lights, &sp));
819 let (sax,say,pa)=self.camera.project(a[0],a[1],a[2]);
820 let (sbx,sby,pb)=self.camera.project(b[0],b[1],b[2]);
821 let (scx,scy,pc)=self.camera.project(c[0],c[1],c[2]);
822 let depth=(pa+pb+pc)/3.0;
823 self.depth_queue.push_triangle_g(depth, sax,say,ca, sbx,sby,cb, scx,scy,cc, bands);
824 }
825 } else {
826 for t in &m.tris {
828 let a = m.verts[t[0] as usize];
829 let b = m.verts[t[1] as usize];
830 let c = m.verts[t[2] as usize];
831 let ux=b[0]-a[0]; let uy=b[1]-a[1]; let uz=b[2]-a[2];
832 let vx=c[0]-a[0]; let vy=c[1]-a[1]; let vz=c[2]-a[2];
833 let normal = [uy*vz-uz*vy, uz*vx-ux*vz, ux*vy-uy*vx];
834 let centroid = [(a[0]+b[0]+c[0])/3.0,(a[1]+b[1]+c[1])/3.0,(a[2]+b[2]+c[2])/3.0];
835 let lit = crate::gfx::light::compute_lit_color(self.color, normal, centroid, &self.lights, self.ambient);
836 let da=self.camera.depth(a[0],a[1],a[2]);
837 let db=self.camera.depth(b[0],b[1],b[2]);
838 let dc=self.camera.depth(c[0],c[1],c[2]);
839 if da<=near || db<=near || dc<=near { continue; }
840 let (sax,say,pa)=self.camera.project(a[0],a[1],a[2]);
841 let (sbx,sby,pb)=self.camera.project(b[0],b[1],b[2]);
842 let (scx,scy,pc)=self.camera.project(c[0],c[1],c[2]);
843 let depth=(pa+pb+pc)/3.0;
844 self.depth_queue.push_triangle(depth, lit, sax,say, sbx,sby, scx,scy);
845 }
846 }
847 }
848
849 if mode == 1 || mode == 2 {
850 let color = self.color;
851 let bias = if mode == 2 { 0.03 } else { 0.0 };
853 for e in &m.edges {
854 let mut a = m.verts[e[0] as usize];
855 let mut b = m.verts[e[1] as usize];
856 let da=self.camera.depth(a[0],a[1],a[2]);
857 let db=self.camera.depth(b[0],b[1],b[2]);
858 if da<=near && db<=near { continue; }
859 if da<=near {
860 let t=(near-da)/(db-da);
861 a=[a[0]+t*(b[0]-a[0]), a[1]+t*(b[1]-a[1]), a[2]+t*(b[2]-a[2])];
862 } else if db<=near {
863 let t=(near-da)/(db-da);
864 b=[a[0]+t*(b[0]-a[0]), a[1]+t*(b[1]-a[1]), a[2]+t*(b[2]-a[2])];
865 }
866 let (sax,say,pa)=self.camera.project(a[0],a[1],a[2]);
867 let (sbx,sby,pb)=self.camera.project(b[0],b[1],b[2]);
868 let depth=(pa+pb)/2.0 - bias;
869 self.depth_queue.push_line(depth, color, sax,say, sbx,sby);
870 }
871 }
872 }
873}