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 vin = [(a, da), (b, db), (c, dc)];
1148 let mut clip: [[f32; 3]; 4] = [[0.0; 3]; 4];
1149 let mut cn = 0usize;
1150 let mut i = 0;
1151 while i < 3 {
1152 let (pa, pad) = vin[i];
1153 let (pb, pbd) = vin[(i + 1) % 3];
1154 let ain = pad > near;
1155 let bin = pbd > near;
1156 if ain && cn < 4 {
1157 clip[cn] = pa;
1158 cn += 1;
1159 }
1160 if ain != bin && cn < 4 {
1161 let t = (near - pad) / (pbd - pad);
1162 clip[cn] = [
1163 pa[0] + (pb[0] - pa[0]) * t,
1164 pa[1] + (pb[1] - pa[1]) * t,
1165 pa[2] + (pb[2] - pa[2]) * t,
1166 ];
1167 cn += 1;
1168 }
1169 i += 1;
1170 }
1171 if cn >= 3 {
1172 let col = m.col[ti];
1173 let packed = ((col[0] as u32) << 16) | ((col[1] as u32) << 8) | (col[2] as u32);
1174 let mut proj: [(f32, f32, f32); 4] = [(0.0, 0.0, 0.0); 4];
1175 let mut depth = 0.0f32;
1176 let mut pi = 0;
1177 while pi < cn {
1178 proj[pi] = self.camera.project(clip[pi][0], clip[pi][1], clip[pi][2]);
1179 depth += proj[pi].2;
1180 pi += 1;
1181 }
1182 depth /= cn as f32;
1183 let mut j = 1;
1184 while j + 1 < cn {
1185 self.depth_queue.push_triangle(
1186 depth,
1187 packed,
1188 proj[0].0,
1189 proj[0].1,
1190 proj[j].0,
1191 proj[j].1,
1192 proj[j + 1].0,
1193 proj[j + 1].1,
1194 );
1195 j += 1;
1196 }
1197 }
1198 }
1199 ti += 1;
1200 }
1201 }
1202
1203 pub fn distort(&mut self, amount: f32, t: f32, step: usize) {
1208 let w = self.width;
1209 let h = self.height;
1210 if w < 2 || h < 2 || amount <= 0.0 {
1211 return;
1212 }
1213 let step = step.max(1);
1214 if self.distort_buf.len() != w * h {
1221 self.distort_buf.clear();
1222 self.distort_buf.resize(w * h, 0);
1223 }
1224 let mut src = std::mem::take(&mut self.distort_buf);
1225 std::mem::swap(&mut self.buffer, &mut src);
1226 let a = amount;
1227 let mut rdx = vec![0i32; h];
1229 let mut rdy = vec![0i32; h];
1230 for y in 0..h {
1231 let fy = y as f32;
1232 rdx[y] =
1233 ((fy * 0.018 + t * 0.8).sin() * a + (fy * 0.005 - t * 0.5).sin() * a * 0.6) as i32;
1234 rdy[y] = ((fy * 0.040 + t * 1.1).sin() * a * 0.4) as i32;
1235 }
1236 let mut cdy = vec![0i32; w];
1239 let mut cdx = vec![0i32; w];
1240 for x in 0..w {
1241 let fx = x as f32;
1242 cdy[x] =
1243 ((fx * 0.020 + t * 0.7).sin() * a + (fx * 0.006 + t * 0.45).sin() * a * 0.6) as i32;
1244 cdx[x] = ((fx * 0.050 + t * 0.9).sin() * a * 0.4) as i32;
1245 }
1246 let wi = w as i32;
1247 let hi = h as i32;
1248 if step == 1 {
1249 let warp_row = |y: usize, out: &mut [u32]| {
1252 let rdx_y = rdx[y];
1253 let ry = rdy[y];
1254 for x in 0..w {
1255 let mut sxi = x as i32 + rdx_y + cdx[x];
1257 if sxi < 0 {
1258 sxi += wi;
1259 } else if sxi >= wi {
1260 sxi -= wi;
1261 }
1262 let mut syi = y as i32 + cdy[x] + ry;
1263 if syi < 0 {
1264 syi += hi;
1265 } else if syi >= hi {
1266 syi -= hi;
1267 }
1268 out[x] = src[syi as usize * w + sxi as usize];
1269 }
1270 };
1271 #[cfg(not(target_arch = "wasm32"))]
1272 {
1273 use rayon::prelude::*;
1274 self.buffer
1275 .par_chunks_mut(w)
1276 .enumerate()
1277 .for_each(|(y, out)| warp_row(y, out));
1278 }
1279 #[cfg(target_arch = "wasm32")]
1280 for (y, out) in self.buffer.chunks_mut(w).enumerate() {
1281 warp_row(y, out);
1282 }
1283 } else {
1284 let mut by = 0;
1291 while by < h {
1292 let yend = (by + step).min(h);
1293 let mut bx = 0;
1294 while bx < w {
1295 let xend = (bx + step).min(w);
1296 let mut sxi = bx as i32 + rdx[by] + cdx[bx];
1297 if sxi < 0 {
1298 sxi += wi;
1299 } else if sxi >= wi {
1300 sxi -= wi;
1301 }
1302 let mut syi = by as i32 + cdy[bx] + rdy[by];
1303 if syi < 0 {
1304 syi += hi;
1305 } else if syi >= hi {
1306 syi -= hi;
1307 }
1308 let pix = src[syi as usize * w + sxi as usize];
1309 for y in by..yend {
1310 let row = y * w;
1311 for x in bx..xend {
1312 self.buffer[row + x] = pix;
1313 }
1314 }
1315 bx += step;
1316 }
1317 by += step;
1318 }
1319 }
1320 self.distort_buf = src; }
1322
1323 pub fn emit_mesh(&mut self, m: &Mesh, mode: i32) {
1326 let near = -self.camera.zdist + 0.05;
1327
1328 let want_fill = mode == 0 || mode == 2;
1329 if want_fill {
1330 let have_normals = m.normals.len() == m.verts.len() && self.shade_mode != 0;
1331 if have_normals {
1332 let base = ling_graphics::shading::unpack(self.color);
1336 let eye = [self.camera.tx, self.camera.ty, self.camera.tz];
1337 let lights: Vec<ling_graphics::shading::LightS> = self
1338 .lights
1339 .iter()
1340 .map(|l| ling_graphics::shading::LightS {
1341 pos: [l.x, l.y, l.z],
1342 color: [l.r, l.g, l.b],
1343 intensity: l.intensity,
1344 radius: l.radius,
1345 })
1346 .collect();
1347 let mut sp = self.shade;
1348 sp.ambient = self.ambient; if self.shade_mode == 1 {
1350 sp.holo = false;
1351 sp.rim *= 0.4;
1352 }
1353 let bands = sp.bands;
1354 for t in &m.tris {
1355 let ia = t[0] as usize;
1356 let ib = t[1] as usize;
1357 let ic = t[2] as usize;
1358 let a = m.verts[ia];
1359 let b = m.verts[ib];
1360 let c = m.verts[ic];
1361 let da = self.camera.depth(a[0], a[1], a[2]);
1362 let db = self.camera.depth(b[0], b[1], b[2]);
1363 let dc = self.camera.depth(c[0], c[1], c[2]);
1364 if da <= near && db <= near && dc <= near {
1365 continue;
1366 } let la = ling_graphics::shading::lit_vertex(
1369 base,
1370 m.normals[ia],
1371 a,
1372 eye,
1373 &lights,
1374 &sp,
1375 );
1376 let lb = ling_graphics::shading::lit_vertex(
1377 base,
1378 m.normals[ib],
1379 b,
1380 eye,
1381 &lights,
1382 &sp,
1383 );
1384 let lc = ling_graphics::shading::lit_vertex(
1385 base,
1386 m.normals[ic],
1387 c,
1388 eye,
1389 &lights,
1390 &sp,
1391 );
1392 let poly = near_clip_poly(&[(a, la, da), (b, lb, db), (c, lc, dc)], near);
1394 if poly.len() < 3 {
1395 continue;
1396 }
1397 let proj: Vec<(f32, f32, f32, u32)> = poly
1398 .iter()
1399 .map(|(p, col)| {
1400 let (sx, sy, pz) = self.camera.project(p[0], p[1], p[2]);
1401 (sx, sy, pz, ling_graphics::shading::pack(*col))
1402 })
1403 .collect();
1404 let mut k = 1;
1405 while k + 1 < proj.len() {
1406 self.depth_queue.push_triangle_g_zv(
1407 proj[0].0,
1408 proj[0].1,
1409 proj[0].2,
1410 proj[0].3,
1411 proj[k].0,
1412 proj[k].1,
1413 proj[k].2,
1414 proj[k].3,
1415 proj[k + 1].0,
1416 proj[k + 1].1,
1417 proj[k + 1].2,
1418 proj[k + 1].3,
1419 bands,
1420 );
1421 k += 1;
1422 }
1423 }
1424 } else {
1425 for t in &m.tris {
1427 let a = m.verts[t[0] as usize];
1428 let b = m.verts[t[1] as usize];
1429 let c = m.verts[t[2] as usize];
1430 let ux = b[0] - a[0];
1431 let uy = b[1] - a[1];
1432 let uz = b[2] - a[2];
1433 let vx = c[0] - a[0];
1434 let vy = c[1] - a[1];
1435 let vz = c[2] - a[2];
1436 let normal = [uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx];
1437 let centroid = [
1438 (a[0] + b[0] + c[0]) / 3.0,
1439 (a[1] + b[1] + c[1]) / 3.0,
1440 (a[2] + b[2] + c[2]) / 3.0,
1441 ];
1442 let lit = if self.flat_shade {
1443 self.color
1444 } else {
1445 crate::gfx::light::compute_lit_color(
1446 self.color,
1447 normal,
1448 centroid,
1449 &self.lights,
1450 self.ambient,
1451 )
1452 };
1453 let da = self.camera.depth(a[0], a[1], a[2]);
1454 let db = self.camera.depth(b[0], b[1], b[2]);
1455 let dc = self.camera.depth(c[0], c[1], c[2]);
1456 if da <= near && db <= near && dc <= near {
1457 continue;
1458 } let poly = near_clip_poly(
1461 &[(a, [0.0; 3], da), (b, [0.0; 3], db), (c, [0.0; 3], dc)],
1462 near,
1463 );
1464 if poly.len() < 3 {
1465 continue;
1466 }
1467 let proj: Vec<(f32, f32, f32)> = poly
1468 .iter()
1469 .map(|(p, _)| self.camera.project(p[0], p[1], p[2]))
1470 .collect();
1471 let mut k = 1;
1472 while k + 1 < proj.len() {
1473 self.depth_queue.push_triangle_zv(
1474 lit,
1475 proj[0].0,
1476 proj[0].1,
1477 proj[0].2,
1478 proj[k].0,
1479 proj[k].1,
1480 proj[k].2,
1481 proj[k + 1].0,
1482 proj[k + 1].1,
1483 proj[k + 1].2,
1484 );
1485 k += 1;
1486 }
1487 }
1488 }
1489 }
1490
1491 if mode == 1 || mode == 2 {
1492 let color = self.color;
1493 let bias = if mode == 2 { 0.03 } else { 0.0 };
1495 for e in &m.edges {
1496 let mut a = m.verts[e[0] as usize];
1497 let mut b = m.verts[e[1] as usize];
1498 let da = self.camera.depth(a[0], a[1], a[2]);
1499 let db = self.camera.depth(b[0], b[1], b[2]);
1500 if da <= near && db <= near {
1501 continue;
1502 }
1503 if da <= near {
1504 let t = (near - da) / (db - da);
1505 a = [
1506 a[0] + t * (b[0] - a[0]),
1507 a[1] + t * (b[1] - a[1]),
1508 a[2] + t * (b[2] - a[2]),
1509 ];
1510 } else if db <= near {
1511 let t = (near - da) / (db - da);
1512 b = [
1513 a[0] + t * (b[0] - a[0]),
1514 a[1] + t * (b[1] - a[1]),
1515 a[2] + t * (b[2] - a[2]),
1516 ];
1517 }
1518 let (sax, say, pa) = self.camera.project(a[0], a[1], a[2]);
1519 let (sbx, sby, pb) = self.camera.project(b[0], b[1], b[2]);
1520 let depth = (pa + pb) / 2.0 - bias;
1521 self.depth_queue.push_line(depth, color, sax, say, sbx, sby);
1522 }
1523 }
1524 }
1525}
1526
1527fn near_clip_poly(vin: &[([f32; 3], [f32; 3], f32)], near: f32) -> Vec<([f32; 3], [f32; 3])> {
1533 let n = vin.len();
1534 let mut out: Vec<([f32; 3], [f32; 3])> = Vec::with_capacity(n + 1);
1535 for i in 0..n {
1536 let a = &vin[i];
1537 let b = &vin[(i + 1) % n];
1538 let ain = a.2 > near;
1539 let bin = b.2 > near;
1540 if ain {
1541 out.push((a.0, a.1));
1542 }
1543 if ain != bin {
1544 let t = (near - a.2) / (b.2 - a.2);
1545 let lerp3 = |p: [f32; 3], q: [f32; 3]| {
1546 [
1547 p[0] + (q[0] - p[0]) * t,
1548 p[1] + (q[1] - p[1]) * t,
1549 p[2] + (q[2] - p[2]) * t,
1550 ]
1551 };
1552 out.push((lerp3(a.0, b.0), lerp3(a.1, b.1)));
1553 }
1554 }
1555 out
1556}