1use super::GfxState;
16use std::collections::HashSet;
17use std::f32::consts::PI;
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) {
37 self.tris.push([a, b, c]);
38 }
39 fn edge(&mut self, a: u32, b: u32) {
40 self.edges.push([a, b]);
41 }
42
43 fn face(&mut self, idx: &[u32]) {
45 for k in 1..idx.len() - 1 {
46 self.tris.push([idx[0], idx[k], idx[k + 1]]);
47 }
48 for k in 0..idx.len() {
49 self.edges.push([idx[k], idx[(k + 1) % idx.len()]]);
50 }
51 }
52
53 fn edges_from_tris(&mut self) {
55 let mut seen: HashSet<(u32, u32)> = HashSet::new();
56 for t in &self.tris {
57 for &(a, b) in &[(t[0], t[1]), (t[1], t[2]), (t[2], t[0])] {
58 let k = if a < b { (a, b) } else { (b, a) };
59 if seen.insert(k) {
60 self.edges.push([k.0, k.1]);
61 }
62 }
63 }
64 }
65
66 fn compute_smooth_normals(&mut self) {
70 let mut n = vec![[0.0f32; 3]; self.verts.len()];
71 for t in &self.tris {
72 let a = self.verts[t[0] as usize];
73 let b = self.verts[t[1] as usize];
74 let c = self.verts[t[2] as usize];
75 let u = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
76 let v = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
77 let f = [
78 u[1] * v[2] - u[2] * v[1],
79 u[2] * v[0] - u[0] * v[2],
80 u[0] * v[1] - u[1] * v[0],
81 ];
82 for &i in t {
83 let i = i as usize;
84 n[i][0] += f[0];
85 n[i][1] += f[1];
86 n[i][2] += f[2];
87 }
88 }
89 for p in &mut n {
90 let l = (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt();
91 if l > 1e-8 {
92 p[0] /= l;
93 p[1] /= l;
94 p[2] /= l;
95 }
96 }
97 self.normals = n;
98 }
99
100 fn transform(&mut self, c: [f32; 9]) {
102 let (cx, cy, cz) = (c[0], c[1], c[2]);
103 let (sx, sy, sz) = (c[3], c[4], c[5]);
104 let (rx, ry, rz) = (c[6], c[7], c[8]);
105 let (srx, crx) = rx.sin_cos();
106 let (sry, cry) = ry.sin_cos();
107 let (srz, crz) = rz.sin_cos();
108 for p in &mut self.verts {
109 let mut x = p[0] * sx;
110 let mut y = p[1] * sy;
111 let mut z = p[2] * sz;
112 let (ny, nz) = (y * crx - z * srx, y * srx + z * crx);
114 y = ny;
115 z = nz;
116 let (nx, nz2) = (x * cry + z * sry, -x * sry + z * cry);
118 x = nx;
119 z = nz2;
120 let (nx2, ny2) = (x * crz - y * srz, x * srz + y * crz);
122 x = nx2;
123 y = ny2;
124 *p = [x + cx, y + cy, z + cz];
125 }
126 }
127}
128
129#[inline]
131fn iarg(v: f32, default: i32) -> i32 {
132 if v > 0.5 {
133 v.round() as i32
134 } else {
135 default
136 }
137}
138#[inline]
139fn farg(v: f32, default: f32) -> f32 {
140 if v > 1e-6 {
141 v
142 } else {
143 default
144 }
145}
146
147fn cube() -> Mesh {
150 let mut m = Mesh::default();
151 let s = 1.0;
152 let p = [
153 m.v(-s, -s, -s),
154 m.v(s, -s, -s),
155 m.v(s, s, -s),
156 m.v(-s, s, -s), m.v(-s, -s, s),
158 m.v(s, -s, s),
159 m.v(s, s, s),
160 m.v(-s, s, s), ];
162 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
169}
170
171fn tetrahedron() -> Mesh {
172 let mut m = Mesh::default();
173 let a = 1.0;
174 let p = [m.v(a, a, a), m.v(a, -a, -a), m.v(-a, a, -a), m.v(-a, -a, a)];
175 m.face(&[p[0], p[1], p[2]]);
176 m.face(&[p[0], p[3], p[1]]);
177 m.face(&[p[0], p[2], p[3]]);
178 m.face(&[p[1], p[3], p[2]]);
179 m
180}
181
182fn octahedron() -> Mesh {
183 let mut m = Mesh::default();
184 let p = [
185 m.v(1.0, 0.0, 0.0),
186 m.v(-1.0, 0.0, 0.0),
187 m.v(0.0, 1.0, 0.0),
188 m.v(0.0, -1.0, 0.0),
189 m.v(0.0, 0.0, 1.0),
190 m.v(0.0, 0.0, -1.0),
191 ];
192 m.face(&[p[0], p[2], p[4]]);
193 m.face(&[p[2], p[1], p[4]]);
194 m.face(&[p[1], p[3], p[4]]);
195 m.face(&[p[3], p[0], p[4]]);
196 m.face(&[p[2], p[0], p[5]]);
197 m.face(&[p[1], p[2], p[5]]);
198 m.face(&[p[3], p[1], p[5]]);
199 m.face(&[p[0], p[3], p[5]]);
200 m
201}
202
203fn icosahedron_raw() -> Mesh {
204 let mut m = Mesh::default();
205 let t = (1.0 + 5.0_f32.sqrt()) / 2.0;
206 let s = 1.0 / (1.0 + t * t).sqrt(); let vs = [
208 [-1., t, 0.],
209 [1., t, 0.],
210 [-1., -t, 0.],
211 [1., -t, 0.],
212 [0., -1., t],
213 [0., 1., t],
214 [0., -1., -t],
215 [0., 1., -t],
216 [t, 0., -1.],
217 [t, 0., 1.],
218 [-t, 0., -1.],
219 [-t, 0., 1.],
220 ];
221 for v in vs {
222 m.v(v[0] * s, v[1] * s, v[2] * s);
223 }
224 let f = [
225 [0, 11, 5],
226 [0, 5, 1],
227 [0, 1, 7],
228 [0, 7, 10],
229 [0, 10, 11],
230 [1, 5, 9],
231 [5, 11, 4],
232 [11, 10, 2],
233 [10, 7, 6],
234 [7, 1, 8],
235 [3, 9, 4],
236 [3, 4, 2],
237 [3, 2, 6],
238 [3, 6, 8],
239 [3, 8, 9],
240 [4, 9, 5],
241 [2, 4, 11],
242 [6, 2, 10],
243 [8, 6, 7],
244 [9, 8, 1],
245 ];
246 for t in f {
247 m.tri(t[0], t[1], t[2]);
248 }
249 m
250}
251
252fn icosahedron() -> Mesh {
253 let mut m = icosahedron_raw();
254 m.edges_from_tris();
255 m
256}
257
258fn icosphere(subdiv: i32) -> Mesh {
259 let mut m = icosahedron_raw();
260 let n = subdiv.clamp(0, 4);
261 for _ in 0..n {
262 let mut nm = Mesh::default();
263 let mut mid: std::collections::HashMap<(u32, u32), u32> = std::collections::HashMap::new();
264 for v in &m.verts {
265 nm.verts.push(*v);
266 }
267 let midpoint = |nm: &mut Mesh,
268 a: u32,
269 b: u32,
270 mid: &mut std::collections::HashMap<(u32, u32), u32>|
271 -> u32 {
272 let key = if a < b { (a, b) } else { (b, a) };
273 if let Some(&i) = mid.get(&key) {
274 return i;
275 }
276 let pa = nm.verts[a as usize];
277 let pb = nm.verts[b as usize];
278 let mut mp = [
279 (pa[0] + pb[0]) / 2.0,
280 (pa[1] + pb[1]) / 2.0,
281 (pa[2] + pb[2]) / 2.0,
282 ];
283 let l = (mp[0] * mp[0] + mp[1] * mp[1] + mp[2] * mp[2]).sqrt();
284 mp = [mp[0] / l, mp[1] / l, mp[2] / l];
285 let i = nm.verts.len() as u32;
286 nm.verts.push(mp);
287 mid.insert(key, i);
288 i
289 };
290 for t in &m.tris {
291 let a = midpoint(&mut nm, t[0], t[1], &mut mid);
292 let b = midpoint(&mut nm, t[1], t[2], &mut mid);
293 let c = midpoint(&mut nm, t[2], t[0], &mut mid);
294 nm.tri(t[0], a, c);
295 nm.tri(t[1], b, a);
296 nm.tri(t[2], c, b);
297 nm.tri(a, b, c);
298 }
299 m = nm;
300 }
301 m.edges_from_tris();
302 m
303}
304
305fn dodecahedron() -> Mesh {
306 let mut m = Mesh::default();
307 let phi = (1.0 + 5.0_f32.sqrt()) / 2.0;
308 let b = 1.0 / phi;
309 let c = phi;
310 let r = (3.0_f32).sqrt(); let s = 1.0 / r;
312 let vs = [
313 [1., 1., 1.],
314 [1., 1., -1.],
315 [1., -1., 1.],
316 [1., -1., -1.],
317 [-1., 1., 1.],
318 [-1., 1., -1.],
319 [-1., -1., 1.],
320 [-1., -1., -1.],
321 [0., b, c],
322 [0., b, -c],
323 [0., -b, c],
324 [0., -b, -c],
325 [b, c, 0.],
326 [b, -c, 0.],
327 [-b, c, 0.],
328 [-b, -c, 0.],
329 [c, 0., b],
330 [c, 0., -b],
331 [-c, 0., b],
332 [-c, 0., -b],
333 ];
334 for v in vs {
335 m.v(v[0] * s, v[1] * s, v[2] * s);
336 }
337 let faces: [[u32; 5]; 12] = [
338 [0, 8, 10, 2, 16],
339 [0, 16, 17, 1, 12],
340 [0, 12, 14, 4, 8],
341 [1, 9, 5, 14, 12],
342 [1, 17, 3, 11, 9],
343 [2, 10, 6, 15, 13],
344 [2, 13, 3, 17, 16],
345 [3, 13, 15, 7, 11],
346 [4, 14, 5, 19, 18],
347 [4, 18, 6, 10, 8],
348 [5, 9, 11, 7, 19],
349 [6, 18, 19, 7, 15],
350 ];
351 for f in faces {
352 m.face(&f);
353 }
354 m
355}
356
357fn uv_sphere(seg: i32, rings: i32) -> Mesh {
360 let mut m = Mesh::default();
361 let seg = seg.clamp(3, 128);
362 let rings = rings.clamp(2, 128);
363 for r in 0..=rings {
364 let v = r as f32 / rings as f32;
365 let theta = v * PI; let (st, ct) = theta.sin_cos();
367 for s in 0..=seg {
368 let u = s as f32 / seg as f32;
369 let phi = u * 2.0 * PI;
370 let (sp, cp) = phi.sin_cos();
371 m.v(st * cp, ct, st * sp);
372 }
373 }
374 let stride = seg + 1;
375 for r in 0..rings {
376 for s in 0..seg {
377 let a = (r * stride + s) as u32;
378 let b = (r * stride + s + 1) as u32;
379 let cc = ((r + 1) * stride + s) as u32;
380 let d = ((r + 1) * stride + s + 1) as u32;
381 m.tri(a, cc, b);
382 m.tri(b, cc, d);
383 }
384 }
385 m.edges_from_tris();
386 m
387}
388
389fn dome(seg: i32, rings: i32) -> Mesh {
390 let mut m = Mesh::default();
392 let seg = seg.clamp(3, 128);
393 let rings = rings.clamp(1, 128);
394 for r in 0..=rings {
395 let v = r as f32 / rings as f32;
396 let theta = v * (PI / 2.0); let (st, ct) = theta.sin_cos();
398 for s in 0..=seg {
399 let phi = s as f32 / seg as f32 * 2.0 * PI;
400 let (sp, cp) = phi.sin_cos();
401 m.v(st * cp, ct, st * sp);
402 }
403 }
404 let stride = seg + 1;
405 for r in 0..rings {
406 for s in 0..seg {
407 let a = (r * stride + s) as u32;
408 let b = (r * stride + s + 1) as u32;
409 let cc = ((r + 1) * stride + s) as u32;
410 let d = ((r + 1) * stride + s + 1) as u32;
411 m.tri(a, cc, b);
412 m.tri(b, cc, d);
413 }
414 }
415 let centre = m.v(0.0, 0.0, 0.0);
417 for s in 0..seg {
418 let a = ((rings) * stride + s) as u32;
419 let b = ((rings) * stride + s + 1) as u32;
420 m.tri(centre, b, a);
421 }
422 m.edges_from_tris();
423 m
424}
425
426fn cylinder(seg: i32) -> Mesh {
427 let mut m = Mesh::default();
428 let seg = seg.clamp(3, 256);
429 for s in 0..seg {
431 let phi = s as f32 / seg as f32 * 2.0 * PI;
432 let (sp, cp) = phi.sin_cos();
433 m.v(cp, -1.0, sp);
434 m.v(cp, 1.0, sp);
435 }
436 for s in 0..seg {
437 let b0 = (2 * s) as u32;
438 let t0 = (2 * s + 1) as u32;
439 let b1 = (2 * ((s + 1) % seg)) as u32;
440 let t1 = (2 * ((s + 1) % seg) + 1) as u32;
441 m.tri(b0, t0, b1);
442 m.tri(b1, t0, t1);
443 m.edge(b0, b1);
444 m.edge(t0, t1);
445 m.edge(b0, t0);
446 }
447 let cb = m.v(0.0, -1.0, 0.0);
448 let ct = m.v(0.0, 1.0, 0.0);
449 for s in 0..seg {
450 let b0 = (2 * s) as u32;
451 let b1 = (2 * ((s + 1) % seg)) as u32;
452 let t0 = (2 * s + 1) as u32;
453 let t1 = (2 * ((s + 1) % seg) + 1) as u32;
454 m.tri(cb, b1, b0);
455 m.tri(ct, t0, t1);
456 }
457 m
458}
459
460fn cone(seg: i32) -> Mesh {
461 let mut m = Mesh::default();
462 let seg = seg.clamp(3, 256);
463 let apex = m.v(0.0, 1.0, 0.0);
464 let base0 = m.verts.len() as u32;
465 for s in 0..seg {
466 let phi = s as f32 / seg as f32 * 2.0 * PI;
467 let (sp, cp) = phi.sin_cos();
468 m.v(cp, -1.0, sp);
469 }
470 let centre = m.v(0.0, -1.0, 0.0);
471 for s in 0..seg {
472 let a = base0 + s as u32;
473 let b = base0 + ((s + 1) % seg) as u32;
474 m.tri(apex, a, b); m.tri(centre, b, a); m.edge(a, b);
477 m.edge(apex, a);
478 }
479 m
480}
481
482fn capsule(seg: i32, rings: i32) -> Mesh {
483 let mut m = Mesh::default();
485 let seg = seg.clamp(3, 128);
486 let rings = rings.clamp(1, 64);
487 let stride = seg + 1;
488 let mut ring_start = Vec::new();
490 let total_rows = 2 * rings; for row in 0..=total_rows {
492 ring_start.push(m.verts.len() as u32);
493 let (cy_off, theta) = if row <= rings {
494 let v = row as f32 / rings as f32;
496 (1.0, v * PI / 2.0)
497 } else {
498 let v = (row - rings) as f32 / rings as f32;
500 (-1.0, PI / 2.0 + v * PI / 2.0)
501 };
502 let (st, ct) = theta.sin_cos();
503 for s in 0..=seg {
504 let phi = s as f32 / seg as f32 * 2.0 * PI;
505 let (sp, cp) = phi.sin_cos();
506 m.v(st * cp, cy_off + ct, st * sp);
507 }
508 }
509 for row in 0..total_rows as usize {
510 for s in 0..seg {
511 let a = ring_start[row] + s as u32;
512 let b = ring_start[row] + s as u32 + 1;
513 let c = ring_start[row + 1] + s as u32;
514 let d = ring_start[row + 1] + s as u32 + 1;
515 m.tri(a, c, b);
516 m.tri(b, c, d);
517 }
518 }
519 let _ = stride;
520 m.edges_from_tris();
521 m
522}
523
524fn torus(seg: i32, sides: i32, tube: f32) -> Mesh {
525 let mut m = Mesh::default();
526 let seg = seg.clamp(3, 256); let sides = sides.clamp(3, 128); let tube = tube.clamp(0.02, 0.9);
529 for i in 0..seg {
530 let u = i as f32 / seg as f32 * 2.0 * PI;
531 let (su, cu) = u.sin_cos();
532 for j in 0..sides {
533 let v = j as f32 / sides as f32 * 2.0 * PI;
534 let (sv, cv) = v.sin_cos();
535 let r = 1.0 - tube + tube * cv;
536 m.v(r * cu, tube * sv, r * su);
537 }
538 }
539 for i in 0..seg {
540 for j in 0..sides {
541 let a = (i * sides + j) as u32;
542 let b = (i * sides + (j + 1) % sides) as u32;
543 let c = (((i + 1) % seg) * sides + j) as u32;
544 let d = (((i + 1) % seg) * sides + (j + 1) % sides) as u32;
545 m.tri(a, c, b);
546 m.tri(b, c, d);
547 }
548 }
549 m.edges_from_tris();
550 m
551}
552
553fn pyramid(sides: i32) -> Mesh {
556 let mut m = Mesh::default();
557 let sides = sides.clamp(3, 128);
558 let apex = m.v(0.0, 1.0, 0.0);
559 let base0 = m.verts.len() as u32;
560 let mut ring = Vec::new();
561 for s in 0..sides {
562 let phi = s as f32 / sides as f32 * 2.0 * PI;
563 let (sp, cp) = phi.sin_cos();
564 ring.push(m.v(cp, -1.0, sp));
565 }
566 for s in 0..sides as usize {
567 let a = ring[s];
568 let b = ring[(s + 1) % sides as usize];
569 m.tri(apex, a, b);
570 m.edge(a, b);
571 m.edge(apex, a);
572 }
573 let mut rev: Vec<u32> = ring.clone();
575 rev.reverse();
576 for k in 1..rev.len() - 1 {
577 m.tri(rev[0], rev[k], rev[k + 1]);
578 }
579 let _ = base0;
580 m
581}
582
583fn prism(sides: i32) -> Mesh {
584 let mut m = Mesh::default();
585 let sides = sides.clamp(3, 128);
586 let mut bot = Vec::new();
587 let mut top = Vec::new();
588 for s in 0..sides {
589 let phi = s as f32 / sides as f32 * 2.0 * PI;
590 let (sp, cp) = phi.sin_cos();
591 bot.push(m.v(cp, -1.0, sp));
592 top.push(m.v(cp, 1.0, sp));
593 }
594 let n = sides as usize;
595 for s in 0..n {
596 let b0 = bot[s];
597 let b1 = bot[(s + 1) % n];
598 let t0 = top[s];
599 let t1 = top[(s + 1) % n];
600 m.tri(b0, t0, b1);
601 m.tri(b1, t0, t1);
602 m.edge(b0, b1);
603 m.edge(t0, t1);
604 m.edge(b0, t0);
605 }
606 for k in 1..n - 1 {
607 m.tri(top[0], top[k], top[k + 1]);
608 }
609 let mut rb: Vec<u32> = bot.clone();
610 rb.reverse();
611 for k in 1..rb.len() - 1 {
612 m.tri(rb[0], rb[k], rb[k + 1]);
613 }
614 m
615}
616
617fn frustum(sides: i32, top_ratio: f32) -> Mesh {
618 let mut m = Mesh::default();
619 let sides = sides.clamp(3, 256);
620 let tr = top_ratio.clamp(0.0, 1.0);
621 let mut bot = Vec::new();
622 let mut top = Vec::new();
623 for s in 0..sides {
624 let phi = s as f32 / sides as f32 * 2.0 * PI;
625 let (sp, cp) = phi.sin_cos();
626 bot.push(m.v(cp, -1.0, sp));
627 top.push(m.v(cp * tr, 1.0, sp * tr));
628 }
629 let n = sides as usize;
630 for s in 0..n {
631 let b0 = bot[s];
632 let b1 = bot[(s + 1) % n];
633 let t0 = top[s];
634 let t1 = top[(s + 1) % n];
635 m.tri(b0, t0, b1);
636 m.tri(b1, t0, t1);
637 m.edge(b0, b1);
638 m.edge(t0, t1);
639 m.edge(b0, t0);
640 }
641 if tr > 0.001 {
642 for k in 1..n - 1 {
643 m.tri(top[0], top[k], top[k + 1]);
644 }
645 }
646 let mut rb: Vec<u32> = bot.clone();
647 rb.reverse();
648 for k in 1..rb.len() - 1 {
649 m.tri(rb[0], rb[k], rb[k + 1]);
650 }
651 m
652}
653
654fn gear(teeth: i32, tooth: f32) -> Mesh {
657 let mut m = Mesh::default();
659 let teeth = teeth.clamp(3, 96);
660 let tooth = tooth.clamp(0.02, 0.6);
661 let pts = teeth * 4; let mut bot = Vec::new();
663 let mut top = Vec::new();
664 for i in 0..pts {
665 let phi = i as f32 / pts as f32 * 2.0 * PI;
666 let phase = (i % 4) as f32;
668 let r = if phase < 2.0 { 1.0 } else { 1.0 - tooth };
669 let (sp, cp) = phi.sin_cos();
670 bot.push(m.v(cp * r, -1.0, sp * r));
671 top.push(m.v(cp * r, 1.0, sp * r));
672 }
673 let n = pts as usize;
674 for s in 0..n {
675 let b0 = bot[s];
676 let b1 = bot[(s + 1) % n];
677 let t0 = top[s];
678 let t1 = top[(s + 1) % n];
679 m.tri(b0, t0, b1);
680 m.tri(b1, t0, t1); m.edge(b0, b1);
682 m.edge(t0, t1);
683 m.edge(b0, t0);
684 }
685 let cb = m.v(0.0, -1.0, 0.0);
686 let ct = m.v(0.0, 1.0, 0.0);
687 for s in 0..n {
688 let b0 = bot[s];
689 let b1 = bot[(s + 1) % n];
690 let t0 = top[s];
691 let t1 = top[(s + 1) % n];
692 m.tri(cb, b1, b0);
693 m.tri(ct, t0, t1); }
695 m
696}
697
698fn gyro(rings: i32) -> Mesh {
699 let mut m = Mesh::default();
701 let rings = rings.clamp(1, 6);
702 for k in 0..rings {
703 let scale = 1.0 - k as f32 * (0.8 / rings as f32);
704 let mut ring = torus(40, 8, 0.06 / scale.max(0.2));
705 let rot = match k % 3 {
707 0 => [0.0, 0.0, 0.0],
708 1 => [PI / 2.0, 0.0, 0.0],
709 _ => [0.0, 0.0, PI / 2.0],
710 };
711 ring.transform([0.0, 0.0, 0.0, scale, scale, scale, rot[0], rot[1], rot[2]]);
712 let base = m.verts.len() as u32;
713 for v in &ring.verts {
714 m.verts.push(*v);
715 }
716 for t in &ring.tris {
717 m.tri(t[0] + base, t[1] + base, t[2] + base);
718 }
719 for e in &ring.edges {
720 m.edge(e[0] + base, e[1] + base);
721 }
722 }
723 m
724}
725
726fn append_mesh(dst: &mut Mesh, src: &Mesh) {
729 let base = dst.verts.len() as u32;
730 for v in &src.verts {
731 dst.verts.push(*v);
732 }
733 for t in &src.tris {
734 dst.tri(t[0] + base, t[1] + base, t[2] + base);
735 }
736 for e in &src.edges {
737 dst.edge(e[0] + base, e[1] + base);
738 }
739}
740
741fn box_between(x0: f32, x1: f32, y0: f32, y1: f32, z0: f32, z1: f32) -> Mesh {
742 let mut m = Mesh::default();
743 let p = [
744 m.v(x0, y0, z0),
745 m.v(x1, y0, z0),
746 m.v(x1, y1, z0),
747 m.v(x0, y1, z0),
748 m.v(x0, y0, z1),
749 m.v(x1, y0, z1),
750 m.v(x1, y1, z1),
751 m.v(x0, y1, z1),
752 ];
753 m.face(&[p[0], p[1], p[2], p[3]]);
754 m.face(&[p[5], p[4], p[7], p[6]]);
755 m.face(&[p[4], p[0], p[3], p[7]]);
756 m.face(&[p[1], p[5], p[6], p[2]]);
757 m.face(&[p[4], p[5], p[1], p[0]]);
758 m.face(&[p[3], p[2], p[6], p[7]]);
759 m
760}
761
762fn helix(turns: i32, tube: f32, sides: i32) -> Mesh {
764 let mut m = Mesh::default();
765 let turns = turns.clamp(1, 24);
766 let sides = sides.clamp(3, 32);
767 let tube = tube.clamp(0.02, 0.5);
768 let seg_per = 24;
769 let total = turns * seg_per;
770 for i in 0..=total {
771 let ang = (i as f32 / seg_per as f32) * 2.0 * PI;
772 let y = -1.0 + 2.0 * (i as f32 / total as f32);
773 let cen = [ang.cos(), y, ang.sin()];
774 let radial = [ang.cos(), 0.0, ang.sin()];
775 let up = [0.0, 1.0, 0.0];
776 for j in 0..sides {
777 let v = j as f32 / sides as f32 * 2.0 * PI;
778 let (sv, cv) = v.sin_cos();
779 m.v(
780 cen[0] + tube * (cv * radial[0] + sv * up[0]),
781 cen[1] + tube * (cv * radial[1] + sv * up[1]),
782 cen[2] + tube * (cv * radial[2] + sv * up[2]),
783 );
784 }
785 }
786 let s = sides;
787 for i in 0..total {
788 for j in 0..sides {
789 let a = (i * s + j) as u32;
790 let b = (i * s + (j + 1) % s) as u32;
791 let c = ((i + 1) * s + j) as u32;
792 let d = ((i + 1) * s + (j + 1) % s) as u32;
793 m.tri(a, c, b);
794 m.tri(b, c, d);
795 }
796 }
797 m.edges_from_tris();
798 m
799}
800
801fn arch(segs: i32, tube: f32) -> Mesh {
803 let mut m = Mesh::default();
804 let segs = segs.clamp(6, 128);
805 let sides = 10i32;
806 let tube = tube.clamp(0.05, 0.4);
807 for i in 0..=segs {
808 let a = PI * (i as f32 / segs as f32); let cen = [a.cos(), a.sin(), 0.0];
810 let radial = [a.cos(), a.sin(), 0.0];
811 let binorm = [0.0, 0.0, 1.0];
812 for j in 0..sides {
813 let v = j as f32 / sides as f32 * 2.0 * PI;
814 let (sv, cv) = v.sin_cos();
815 m.v(
816 cen[0] + tube * (cv * radial[0] + sv * binorm[0]),
817 cen[1] + tube * (cv * radial[1] + sv * binorm[1]),
818 cen[2] + tube * (cv * radial[2] + sv * binorm[2]),
819 );
820 }
821 }
822 for i in 0..segs {
823 for j in 0..sides {
824 let a = (i * sides + j) as u32;
825 let b = (i * sides + (j + 1) % sides) as u32;
826 let c = ((i + 1) * sides + j) as u32;
827 let d = ((i + 1) * sides + (j + 1) % sides) as u32;
828 m.tri(a, c, b);
829 m.tri(b, c, d);
830 }
831 }
832 m.edges_from_tris();
833 m
834}
835
836fn stairs(steps: i32) -> Mesh {
838 let mut m = Mesh::default();
839 let steps = steps.clamp(2, 40);
840 let sh = 2.0 / steps as f32;
841 let sd = 2.0 / steps as f32;
842 for i in 0..steps {
843 let y0 = -1.0 + i as f32 * sh;
844 let y1 = y0 + sh;
845 let z0 = -1.0 + i as f32 * sd;
846 let zf = z0 + sd;
847 let blk = box_between(-1.0, 1.0, y0, y1, z0, zf);
848 append_mesh(&mut m, &blk);
849 }
850 m
851}
852
853fn star_prism(points: i32, inner: f32) -> Mesh {
855 let mut m = Mesh::default();
856 let points = points.clamp(3, 32);
857 let inner = inner.clamp(0.1, 0.95);
858 let n = (points * 2) as usize;
859 let mut bot = Vec::new();
860 let mut top = Vec::new();
861 for k in 0..n {
862 let ang = k as f32 / n as f32 * 2.0 * PI;
863 let r = if k % 2 == 0 { 1.0 } else { inner };
864 let (s, c) = ang.sin_cos();
865 bot.push(m.v(c * r, -1.0, s * r));
866 top.push(m.v(c * r, 1.0, s * r));
867 }
868 for k in 0..n {
869 let b0 = bot[k];
870 let b1 = bot[(k + 1) % n];
871 let t0 = top[k];
872 let t1 = top[(k + 1) % n];
873 m.tri(b0, t0, b1);
874 m.tri(b1, t0, t1);
875 m.edge(b0, b1);
876 m.edge(t0, t1);
877 m.edge(b0, t0);
878 }
879 for k in 1..n - 1 {
880 m.tri(top[0], top[k], top[k + 1]);
881 }
882 let mut rb = bot.clone();
883 rb.reverse();
884 for k in 1..rb.len() - 1 {
885 m.tri(rb[0], rb[k], rb[k + 1]);
886 }
887 m
888}
889
890fn capsule_chain(count: i32) -> Mesh {
892 let mut m = Mesh::default();
893 let count = count.clamp(1, 12);
894 let step = 2.0 / count as f32;
895 for i in 0..count {
896 let mut c = capsule(12, 4);
897 let cx = -1.0 + (i as f32 + 0.5) * step;
898 c.transform([
899 cx,
900 0.0,
901 0.0,
902 step * 0.5,
903 step * 0.5,
904 step * 0.5,
905 0.0,
906 0.0,
907 PI / 2.0,
908 ]);
909 append_mesh(&mut m, &c);
910 }
911 m
912}
913
914fn mobius(segs: i32, width: f32) -> Mesh {
916 let mut m = Mesh::default();
917 let segs = segs.clamp(8, 240);
918 let w = width.clamp(0.05, 0.6);
919 for i in 0..=segs {
920 let u = i as f32 / segs as f32 * 2.0 * PI;
921 for &vv in &[-1.0f32, 1.0] {
922 let v = vv * w;
923 let x = (1.0 + v / 2.0 * (u / 2.0).cos()) * u.cos();
924 let y = v / 2.0 * (u / 2.0).sin();
925 let z = (1.0 + v / 2.0 * (u / 2.0).cos()) * u.sin();
926 m.v(x, y, z);
927 }
928 }
929 for i in 0..segs {
930 let a = (2 * i) as u32;
931 let b = (2 * i + 1) as u32;
932 let c = (2 * (i + 1)) as u32;
933 let d = (2 * (i + 1) + 1) as u32;
934 m.tri(a, c, b);
935 m.tri(b, c, d);
936 }
937 m.edges_from_tris();
938 m
939}
940
941pub fn canon(name: &str) -> Option<&'static str> {
944 Some(match name {
945 "cube" | "box" | "立方体" | "方块" | "箱" | "정육면체" | "상자" | "ลูกบาศก์" | "กล่อง" => {
947 "cube"
948 },
949 "sphere" | "球体" | "球" | "구" | "ทรงกลม" => "sphere",
951 "icosphere" | "二十面球" | "アイコ球" | "아이코구체" | "ทรงกลมเหลี่ยม" => {
953 "icosphere"
954 },
955 "dome" | "穹顶" | "ドーム" | "돔" | "โดม" => "dome",
957 "cylinder" | "圆柱" | "円柱" | "원기둥" | "ทรงกระบอก" => {
959 "cylinder"
960 },
961 "cone" | "圆锥" | "円錐" | "원뿔" | "กรวย" => "cone",
963 "capsule" | "胶囊" | "カプセル" | "캡슐" | "แคปซูล" => "capsule",
965 "torus" | "ring" | "圆环" | "トーラス" | "토러스" | "ทอรัส" => "torus",
967 "pyramid" | "金字塔" | "ピラミッド" | "피라미드" | "พีระมิด" => {
969 "pyramid"
970 },
971 "prism" | "棱柱" | "角柱" | "각기둥" | "ปริซึม" => "prism",
973 "frustum" | "棱台" | "錐台" | "원뿔대" | "กรวยตัด" => "frustum",
975 "tetrahedron" | "d4" | "四面体" | "정사면체" | "ทรงสี่หน้า" => {
977 "tetrahedron"
978 },
979 "octahedron" | "d8" | "八面体" | "정팔면체" | "ทรงแปดหน้า" => {
981 "octahedron"
982 },
983 "dodecahedron" | "d12" | "十二面体" | "정십이면체" | "ทรงสิบสองหน้า" => {
985 "dodecahedron"
986 },
987 "icosahedron" | "d20" | "二十面体" | "정이십면체" | "ทรงยี่สิบหน้า" => {
989 "icosahedron"
990 },
991 "gear" | "cog" | "齿轮" | "歯車" | "톱니바퀴" | "เฟือง" => "gear",
993 "gyro" | "陀螺" | "ジャイロ" | "자이로" | "ไจโร" => "gyro",
995 "helix" | "螺旋线" | "らせん" | "나선" | "เกลียว" => "helix",
997 "spring" | "弹簧" | "ばね" | "스프링" | "สปริง" => "spring",
999 "arch" | "拱门" | "アーチ" | "아치" | "ซุ้มโค้ง" => "arch",
1001 "stairs" | "楼梯" | "階段" | "계단" | "บันได" => "stairs",
1003 "star_prism" | "star" | "星柱" | "星型柱" | "별기둥" | "แท่งดาว" => {
1005 "star_prism"
1006 },
1007 "capsule_chain" | "chain" | "胶囊链" | "カプセル鎖" | "캡슐체인" | "โซ่แคปซูล" => {
1009 "capsule_chain"
1010 },
1011 "mobius" | "莫比乌斯" | "メビウス" | "뫼비우스" | "เมอบีอุส" => {
1013 "mobius"
1014 },
1015 _ => return None,
1016 })
1017}
1018
1019pub fn build(kind: &str, c: [f32; 9], e0: f32, e1: f32, e2: f32) -> Option<Mesh> {
1022 let mut m = match kind {
1023 "cube" | "box" => cube(),
1024 "sphere" => uv_sphere(iarg(e0, 16), iarg(e1, 12)),
1025 "icosphere" => icosphere(iarg(e0, 1)),
1026 "dome" => dome(iarg(e0, 24), iarg(e1, 8)),
1027 "cylinder" => cylinder(iarg(e0, 24)),
1028 "cone" => cone(iarg(e0, 24)),
1029 "capsule" => capsule(iarg(e0, 16), iarg(e1, 6)),
1030 "torus" | "ring" => torus(iarg(e0, 32), iarg(e1, 12), farg(e2, 0.35)),
1031 "pyramid" => pyramid(iarg(e0, 4)),
1032 "prism" => prism(iarg(e0, 6)),
1033 "frustum" => frustum(iarg(e0, 24), farg(e1, 0.5)),
1034 "tetrahedron" | "d4" => {
1035 let mut t = tetrahedron();
1036 t.edges = vec![];
1037 t.edges_from_tris();
1038 t
1039 },
1040 "octahedron" | "d8" => {
1041 let mut t = octahedron();
1042 t.edges = vec![];
1043 t.edges_from_tris();
1044 t
1045 },
1046 "dodecahedron" | "d12" => dodecahedron(),
1047 "icosahedron" | "d20" => icosahedron(),
1048 "gear" | "cog" => gear(iarg(e0, 12), farg(e1, 0.25)),
1049 "gyro" => gyro(iarg(e0, 3)),
1050 "helix" => helix(iarg(e0, 3), farg(e1, 0.15), iarg(e2, 8)),
1051 "spring" => helix(iarg(e0, 6), farg(e1, 0.12), iarg(e2, 8)),
1052 "arch" => arch(iarg(e0, 24), farg(e1, 0.18)),
1053 "stairs" => stairs(iarg(e0, 5)),
1054 "star_prism" => star_prism(iarg(e0, 5), farg(e1, 0.5)),
1055 "capsule_chain" => capsule_chain(iarg(e0, 3)),
1056 "mobius" => mobius(iarg(e0, 60), farg(e1, 0.3)),
1057 _ => return None,
1058 };
1059 m.transform(c);
1060 m.compute_smooth_normals();
1061 Some(m)
1062}
1063
1064#[derive(Default, Clone)]
1068pub struct ColorMesh {
1069 pub pos: Vec<[f32; 3]>, pub col: Vec<[u8; 3]>, pub height: f32,
1072}
1073
1074impl GfxState {
1075 #[allow(clippy::too_many_arguments)]
1081 pub fn draw_color_mesh(
1082 &mut self,
1083 m: &ColorMesh,
1084 cx: f32,
1085 cy: f32,
1086 cz: f32,
1087 sc: f32,
1088 yaw: f32,
1089 sway: f32,
1090 arm: f32,
1091 lean: f32,
1092 leg: f32,
1093 tuck: f32,
1094 ) {
1095 let near = -self.camera.zdist + 0.05;
1096 let cs = yaw.cos();
1097 let sn = yaw.sin();
1098 let h = m.height.max(1e-4);
1099 let yc = -0.68 * h; let torso = 0.13 * h;
1101 let elbow = torso + 0.16 * h;
1102 let nt = m.col.len();
1103 let mut ti = 0usize;
1104 while ti < nt {
1105 let base = ti * 3;
1106 let mut wv = [[0.0f32; 3]; 3];
1107 let mut k = 0;
1108 while k < 3 {
1109 let p = m.pos[base + k];
1110 let ax = p[0].abs();
1111 let yb = (1.0 - (p[1] - yc).abs() / (0.30 * h)).clamp(0.0, 1.0); let aw = (((ax - torso) / (0.40 * h)).clamp(0.0, 1.0)) * yb; let ew = (((ax - elbow) / (0.28 * h)).clamp(0.0, 1.0)) * yb; let side = if p[0] >= 0.0 { 1.0 } else { -1.0 };
1115 let bw = (((p[1].abs() / h) - 0.40) / 0.60).clamp(0.0, 1.0); let zlean = lean * bw * bw * h - lean * aw * 0.6 * h;
1119 let lw = (((0.45 * h - p[1].abs()) / (0.45 * h)).clamp(0.0, 1.0)) * (1.0 - aw);
1122 let fw = (((0.16 * h - p[1].abs()) / (0.16 * h)).clamp(0.0, 1.0)) * (1.0 - aw);
1123 let legswing = leg * side * lw;
1124 let mut ylift = 0.0f32;
1125 if legswing > 0.0 {
1126 ylift -= legswing * fw * 0.45 * h;
1127 } ylift -= tuck * lw * 0.22 * h; let xs = p[0] + sway * p[1].abs();
1130 let zs =
1131 p[2] + arm * side * (aw + ew * 0.7) + zlean + legswing + tuck * lw * 0.16 * h;
1132 wv[k] = [
1133 cx + (xs * cs + zs * sn) * sc,
1134 cy + (p[1] + ylift) * sc,
1135 cz + (zs * cs - xs * sn) * sc,
1136 ];
1137 k += 1;
1138 }
1139 let a = wv[0];
1140 let b = wv[1];
1141 let c = wv[2];
1142 let da = self.camera.depth(a[0], a[1], a[2]);
1143 let db = self.camera.depth(b[0], b[1], b[2]);
1144 let dc = self.camera.depth(c[0], c[1], c[2]);
1145 if !(da <= near && db <= near && dc <= near) {
1146 let poly = near_clip_poly(
1147 &[(a, [0.0; 3], da), (b, [0.0; 3], db), (c, [0.0; 3], dc)],
1148 near,
1149 );
1150 if poly.len() >= 3 {
1151 let col = m.col[ti];
1152 let packed = ((col[0] as u32) << 16) | ((col[1] as u32) << 8) | (col[2] as u32);
1153 let proj: Vec<(f32, f32, f32)> = poly
1154 .iter()
1155 .map(|(p, _)| self.camera.project(p[0], p[1], p[2]))
1156 .collect();
1157 let depth = proj.iter().map(|v| v.2).sum::<f32>() / proj.len() as f32;
1158 let mut j = 1;
1159 while j + 1 < proj.len() {
1160 self.depth_queue.push_triangle(
1161 depth,
1162 packed,
1163 proj[0].0,
1164 proj[0].1,
1165 proj[j].0,
1166 proj[j].1,
1167 proj[j + 1].0,
1168 proj[j + 1].1,
1169 );
1170 j += 1;
1171 }
1172 }
1173 }
1174 ti += 1;
1175 }
1176 }
1177
1178 pub fn distort(&mut self, amount: f32, t: f32) {
1183 let w = self.width;
1184 let h = self.height;
1185 if w < 2 || h < 2 || amount <= 0.0 {
1186 return;
1187 }
1188 let src = self.buffer.clone();
1189 let a = amount;
1190 let mut rdx = vec![0i32; h];
1192 let mut rdy = vec![0i32; h];
1193 for y in 0..h {
1194 let fy = y as f32;
1195 rdx[y] =
1196 ((fy * 0.018 + t * 0.8).sin() * a + (fy * 0.005 - t * 0.5).sin() * a * 0.6) as i32;
1197 rdy[y] = ((fy * 0.040 + t * 1.1).sin() * a * 0.4) as i32;
1198 }
1199 let mut cdy = vec![0i32; w];
1202 let mut cdx = vec![0i32; w];
1203 for x in 0..w {
1204 let fx = x as f32;
1205 cdy[x] =
1206 ((fx * 0.020 + t * 0.7).sin() * a + (fx * 0.006 + t * 0.45).sin() * a * 0.6) as i32;
1207 cdx[x] = ((fx * 0.050 + t * 0.9).sin() * a * 0.4) as i32;
1208 }
1209 let wi = w as i32;
1210 let hi = h as i32;
1211 for y in 0..h {
1212 let row = y * w;
1213 let ry = rdy[y];
1214 for x in 0..w {
1215 let mut sxi = x as i32 + rdx[y] + cdx[x];
1217 if sxi < 0 {
1218 sxi += wi;
1219 } else if sxi >= wi {
1220 sxi -= wi;
1221 }
1222 let mut syi = y as i32 + cdy[x] + ry;
1223 if syi < 0 {
1224 syi += hi;
1225 } else if syi >= hi {
1226 syi -= hi;
1227 }
1228 self.buffer[row + x] = src[syi as usize * w + sxi as usize];
1229 }
1230 }
1231 }
1232
1233 pub fn emit_mesh(&mut self, m: &Mesh, mode: i32) {
1236 let near = -self.camera.zdist + 0.05;
1237
1238 let want_fill = mode == 0 || mode == 2;
1239 if want_fill {
1240 let have_normals = m.normals.len() == m.verts.len() && self.shade_mode != 0;
1241 if have_normals {
1242 let base = ling_graphics::shading::unpack(self.color);
1246 let eye = [self.camera.tx, self.camera.ty, self.camera.tz];
1247 let lights: Vec<ling_graphics::shading::LightS> = self
1248 .lights
1249 .iter()
1250 .map(|l| ling_graphics::shading::LightS {
1251 pos: [l.x, l.y, l.z],
1252 color: [l.r, l.g, l.b],
1253 intensity: l.intensity,
1254 radius: l.radius,
1255 })
1256 .collect();
1257 let mut sp = self.shade;
1258 sp.ambient = self.ambient; if self.shade_mode == 1 {
1260 sp.holo = false;
1261 sp.rim *= 0.4;
1262 }
1263 let bands = sp.bands;
1264 for t in &m.tris {
1265 let ia = t[0] as usize;
1266 let ib = t[1] as usize;
1267 let ic = t[2] as usize;
1268 let a = m.verts[ia];
1269 let b = m.verts[ib];
1270 let c = m.verts[ic];
1271 let da = self.camera.depth(a[0], a[1], a[2]);
1272 let db = self.camera.depth(b[0], b[1], b[2]);
1273 let dc = self.camera.depth(c[0], c[1], c[2]);
1274 if da <= near && db <= near && dc <= near {
1275 continue;
1276 } let la = ling_graphics::shading::lit_vertex(
1279 base,
1280 m.normals[ia],
1281 a,
1282 eye,
1283 &lights,
1284 &sp,
1285 );
1286 let lb = ling_graphics::shading::lit_vertex(
1287 base,
1288 m.normals[ib],
1289 b,
1290 eye,
1291 &lights,
1292 &sp,
1293 );
1294 let lc = ling_graphics::shading::lit_vertex(
1295 base,
1296 m.normals[ic],
1297 c,
1298 eye,
1299 &lights,
1300 &sp,
1301 );
1302 let poly = near_clip_poly(&[(a, la, da), (b, lb, db), (c, lc, dc)], near);
1304 if poly.len() < 3 {
1305 continue;
1306 }
1307 let proj: Vec<(f32, f32, f32, u32)> = poly
1308 .iter()
1309 .map(|(p, col)| {
1310 let (sx, sy, pz) = self.camera.project(p[0], p[1], p[2]);
1311 (sx, sy, pz, ling_graphics::shading::pack(*col))
1312 })
1313 .collect();
1314 let mut k = 1;
1315 while k + 1 < proj.len() {
1316 self.depth_queue.push_triangle_g_zv(
1317 proj[0].0,
1318 proj[0].1,
1319 proj[0].2,
1320 proj[0].3,
1321 proj[k].0,
1322 proj[k].1,
1323 proj[k].2,
1324 proj[k].3,
1325 proj[k + 1].0,
1326 proj[k + 1].1,
1327 proj[k + 1].2,
1328 proj[k + 1].3,
1329 bands,
1330 );
1331 k += 1;
1332 }
1333 }
1334 } else {
1335 for t in &m.tris {
1337 let a = m.verts[t[0] as usize];
1338 let b = m.verts[t[1] as usize];
1339 let c = m.verts[t[2] as usize];
1340 let ux = b[0] - a[0];
1341 let uy = b[1] - a[1];
1342 let uz = b[2] - a[2];
1343 let vx = c[0] - a[0];
1344 let vy = c[1] - a[1];
1345 let vz = c[2] - a[2];
1346 let normal = [uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx];
1347 let centroid = [
1348 (a[0] + b[0] + c[0]) / 3.0,
1349 (a[1] + b[1] + c[1]) / 3.0,
1350 (a[2] + b[2] + c[2]) / 3.0,
1351 ];
1352 let lit = crate::gfx::light::compute_lit_color(
1353 self.color,
1354 normal,
1355 centroid,
1356 &self.lights,
1357 self.ambient,
1358 );
1359 let da = self.camera.depth(a[0], a[1], a[2]);
1360 let db = self.camera.depth(b[0], b[1], b[2]);
1361 let dc = self.camera.depth(c[0], c[1], c[2]);
1362 if da <= near && db <= near && dc <= near {
1363 continue;
1364 } let poly = near_clip_poly(
1367 &[(a, [0.0; 3], da), (b, [0.0; 3], db), (c, [0.0; 3], dc)],
1368 near,
1369 );
1370 if poly.len() < 3 {
1371 continue;
1372 }
1373 let proj: Vec<(f32, f32, f32)> = poly
1374 .iter()
1375 .map(|(p, _)| self.camera.project(p[0], p[1], p[2]))
1376 .collect();
1377 let mut k = 1;
1378 while k + 1 < proj.len() {
1379 self.depth_queue.push_triangle_zv(
1380 lit,
1381 proj[0].0,
1382 proj[0].1,
1383 proj[0].2,
1384 proj[k].0,
1385 proj[k].1,
1386 proj[k].2,
1387 proj[k + 1].0,
1388 proj[k + 1].1,
1389 proj[k + 1].2,
1390 );
1391 k += 1;
1392 }
1393 }
1394 }
1395 }
1396
1397 if mode == 1 || mode == 2 {
1398 let color = self.color;
1399 let bias = if mode == 2 { 0.03 } else { 0.0 };
1401 for e in &m.edges {
1402 let mut a = m.verts[e[0] as usize];
1403 let mut b = m.verts[e[1] as usize];
1404 let da = self.camera.depth(a[0], a[1], a[2]);
1405 let db = self.camera.depth(b[0], b[1], b[2]);
1406 if da <= near && db <= near {
1407 continue;
1408 }
1409 if da <= near {
1410 let t = (near - da) / (db - da);
1411 a = [
1412 a[0] + t * (b[0] - a[0]),
1413 a[1] + t * (b[1] - a[1]),
1414 a[2] + t * (b[2] - a[2]),
1415 ];
1416 } else if db <= near {
1417 let t = (near - da) / (db - da);
1418 b = [
1419 a[0] + t * (b[0] - a[0]),
1420 a[1] + t * (b[1] - a[1]),
1421 a[2] + t * (b[2] - a[2]),
1422 ];
1423 }
1424 let (sax, say, pa) = self.camera.project(a[0], a[1], a[2]);
1425 let (sbx, sby, pb) = self.camera.project(b[0], b[1], b[2]);
1426 let depth = (pa + pb) / 2.0 - bias;
1427 self.depth_queue.push_line(depth, color, sax, say, sbx, sby);
1428 }
1429 }
1430 }
1431}
1432
1433fn near_clip_poly(vin: &[([f32; 3], [f32; 3], f32)], near: f32) -> Vec<([f32; 3], [f32; 3])> {
1439 let n = vin.len();
1440 let mut out: Vec<([f32; 3], [f32; 3])> = Vec::with_capacity(n + 1);
1441 for i in 0..n {
1442 let a = &vin[i];
1443 let b = &vin[(i + 1) % n];
1444 let ain = a.2 > near;
1445 let bin = b.2 > near;
1446 if ain {
1447 out.push((a.0, a.1));
1448 }
1449 if ain != bin {
1450 let t = (near - a.2) / (b.2 - a.2);
1451 let lerp3 = |p: [f32; 3], q: [f32; 3]| {
1452 [
1453 p[0] + (q[0] - p[0]) * t,
1454 p[1] + (q[1] - p[1]) * t,
1455 p[2] + (q[2] - p[2]) * t,
1456 ]
1457 };
1458 out.push((lerp3(a.0, b.0), lerp3(a.1, b.1)));
1459 }
1460 }
1461 out
1462}