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
37 fn tri(&mut self, a: u32, b: u32, c: u32) {
38 self.tris.push([a, b, c]);
39 }
40
41 fn edge(&mut self, a: u32, b: u32) {
42 self.edges.push([a, b]);
43 }
44
45 fn face(&mut self, idx: &[u32]) {
47 for k in 1..idx.len() - 1 {
48 self.tris.push([idx[0], idx[k], idx[k + 1]]);
49 }
50 for k in 0..idx.len() {
51 self.edges.push([idx[k], idx[(k + 1) % idx.len()]]);
52 }
53 }
54
55 fn edges_from_tris(&mut self) {
57 let mut seen: HashSet<(u32, u32)> = HashSet::new();
58 for t in &self.tris {
59 for &(a, b) in &[(t[0], t[1]), (t[1], t[2]), (t[2], t[0])] {
60 let k = if a < b { (a, b) } else { (b, a) };
61 if seen.insert(k) {
62 self.edges.push([k.0, k.1]);
63 }
64 }
65 }
66 }
67
68 fn compute_smooth_normals(&mut self) {
72 let mut n = vec![[0.0f32; 3]; self.verts.len()];
73 for t in &self.tris {
74 let a = self.verts[t[0] as usize];
75 let b = self.verts[t[1] as usize];
76 let c = self.verts[t[2] as usize];
77 let u = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
78 let v = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
79 let f = [
80 u[1] * v[2] - u[2] * v[1],
81 u[2] * v[0] - u[0] * v[2],
82 u[0] * v[1] - u[1] * v[0],
83 ];
84 for &i in t {
85 let i = i as usize;
86 n[i][0] += f[0];
87 n[i][1] += f[1];
88 n[i][2] += f[2];
89 }
90 }
91 for p in &mut n {
92 let l = (p[0] * p[0] + p[1] * p[1] + p[2] * p[2]).sqrt();
93 if l > 1e-8 {
94 p[0] /= l;
95 p[1] /= l;
96 p[2] /= l;
97 }
98 }
99 self.normals = n;
100 }
101
102 fn transform(&mut self, c: [f32; 9]) {
104 let (cx, cy, cz) = (c[0], c[1], c[2]);
105 let (sx, sy, sz) = (c[3], c[4], c[5]);
106 let (rx, ry, rz) = (c[6], c[7], c[8]);
107 let (srx, crx) = rx.sin_cos();
108 let (sry, cry) = ry.sin_cos();
109 let (srz, crz) = rz.sin_cos();
110 for p in &mut self.verts {
111 let mut x = p[0] * sx;
112 let mut y = p[1] * sy;
113 let mut z = p[2] * sz;
114 let (ny, nz) = (y * crx - z * srx, y * srx + z * crx);
116 y = ny;
117 z = nz;
118 let (nx, nz2) = (x * cry + z * sry, -x * sry + z * cry);
120 x = nx;
121 z = nz2;
122 let (nx2, ny2) = (x * crz - y * srz, x * srz + y * crz);
124 x = nx2;
125 y = ny2;
126 *p = [x + cx, y + cy, z + cz];
127 }
128 }
129}
130
131#[inline]
133fn iarg(v: f32, default: i32) -> i32 {
134 if v > 0.5 {
135 v.round() as i32
136 } else {
137 default
138 }
139}
140#[inline]
141fn farg(v: f32, default: f32) -> f32 {
142 if v > 1e-6 {
143 v
144 } else {
145 default
146 }
147}
148
149fn cube() -> Mesh {
152 let mut m = Mesh::default();
153 let s = 1.0;
154 let p = [
155 m.v(-s, -s, -s),
156 m.v(s, -s, -s),
157 m.v(s, s, -s),
158 m.v(-s, s, -s), m.v(-s, -s, s),
160 m.v(s, -s, s),
161 m.v(s, s, s),
162 m.v(-s, s, s), ];
164 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
171}
172
173fn tetrahedron() -> Mesh {
174 let mut m = Mesh::default();
175 let a = 1.0;
176 let p = [m.v(a, a, a), m.v(a, -a, -a), m.v(-a, a, -a), m.v(-a, -a, a)];
177 m.face(&[p[0], p[1], p[2]]);
178 m.face(&[p[0], p[3], p[1]]);
179 m.face(&[p[0], p[2], p[3]]);
180 m.face(&[p[1], p[3], p[2]]);
181 m
182}
183
184fn octahedron() -> Mesh {
185 let mut m = Mesh::default();
186 let p = [
187 m.v(1.0, 0.0, 0.0),
188 m.v(-1.0, 0.0, 0.0),
189 m.v(0.0, 1.0, 0.0),
190 m.v(0.0, -1.0, 0.0),
191 m.v(0.0, 0.0, 1.0),
192 m.v(0.0, 0.0, -1.0),
193 ];
194 m.face(&[p[0], p[2], p[4]]);
195 m.face(&[p[2], p[1], p[4]]);
196 m.face(&[p[1], p[3], p[4]]);
197 m.face(&[p[3], p[0], p[4]]);
198 m.face(&[p[2], p[0], p[5]]);
199 m.face(&[p[1], p[2], p[5]]);
200 m.face(&[p[3], p[1], p[5]]);
201 m.face(&[p[0], p[3], p[5]]);
202 m
203}
204
205fn icosahedron_raw() -> Mesh {
206 let mut m = Mesh::default();
207 let t = (1.0 + 5.0_f32.sqrt()) / 2.0;
208 let s = 1.0 / (1.0 + t * t).sqrt(); let vs = [
210 [-1., t, 0.],
211 [1., t, 0.],
212 [-1., -t, 0.],
213 [1., -t, 0.],
214 [0., -1., t],
215 [0., 1., t],
216 [0., -1., -t],
217 [0., 1., -t],
218 [t, 0., -1.],
219 [t, 0., 1.],
220 [-t, 0., -1.],
221 [-t, 0., 1.],
222 ];
223 for v in vs {
224 m.v(v[0] * s, v[1] * s, v[2] * s);
225 }
226 let f = [
227 [0, 11, 5],
228 [0, 5, 1],
229 [0, 1, 7],
230 [0, 7, 10],
231 [0, 10, 11],
232 [1, 5, 9],
233 [5, 11, 4],
234 [11, 10, 2],
235 [10, 7, 6],
236 [7, 1, 8],
237 [3, 9, 4],
238 [3, 4, 2],
239 [3, 2, 6],
240 [3, 6, 8],
241 [3, 8, 9],
242 [4, 9, 5],
243 [2, 4, 11],
244 [6, 2, 10],
245 [8, 6, 7],
246 [9, 8, 1],
247 ];
248 for t in f {
249 m.tri(t[0], t[1], t[2]);
250 }
251 m
252}
253
254fn icosahedron() -> Mesh {
255 let mut m = icosahedron_raw();
256 m.edges_from_tris();
257 m
258}
259
260fn icosphere(subdiv: i32) -> Mesh {
261 let mut m = icosahedron_raw();
262 let n = subdiv.clamp(0, 4);
263 for _ in 0..n {
264 let mut nm = Mesh::default();
265 let mut mid: std::collections::HashMap<(u32, u32), u32> = std::collections::HashMap::new();
266 for v in &m.verts {
267 nm.verts.push(*v);
268 }
269 let midpoint = |nm: &mut Mesh,
270 a: u32,
271 b: u32,
272 mid: &mut std::collections::HashMap<(u32, u32), u32>|
273 -> u32 {
274 let key = if a < b { (a, b) } else { (b, a) };
275 if let Some(&i) = mid.get(&key) {
276 return i;
277 }
278 let pa = nm.verts[a as usize];
279 let pb = nm.verts[b as usize];
280 let mut mp = [
281 (pa[0] + pb[0]) / 2.0,
282 (pa[1] + pb[1]) / 2.0,
283 (pa[2] + pb[2]) / 2.0,
284 ];
285 let l = (mp[0] * mp[0] + mp[1] * mp[1] + mp[2] * mp[2]).sqrt();
286 mp = [mp[0] / l, mp[1] / l, mp[2] / l];
287 let i = nm.verts.len() as u32;
288 nm.verts.push(mp);
289 mid.insert(key, i);
290 i
291 };
292 for t in &m.tris {
293 let a = midpoint(&mut nm, t[0], t[1], &mut mid);
294 let b = midpoint(&mut nm, t[1], t[2], &mut mid);
295 let c = midpoint(&mut nm, t[2], t[0], &mut mid);
296 nm.tri(t[0], a, c);
297 nm.tri(t[1], b, a);
298 nm.tri(t[2], c, b);
299 nm.tri(a, b, c);
300 }
301 m = nm;
302 }
303 m.edges_from_tris();
304 m
305}
306
307fn dodecahedron() -> Mesh {
308 let mut m = Mesh::default();
309 let phi = (1.0 + 5.0_f32.sqrt()) / 2.0;
310 let b = 1.0 / phi;
311 let c = phi;
312 let r = (3.0_f32).sqrt(); let s = 1.0 / r;
314 let vs = [
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 [-1., -1., 1.],
322 [-1., -1., -1.],
323 [0., b, c],
324 [0., b, -c],
325 [0., -b, c],
326 [0., -b, -c],
327 [b, c, 0.],
328 [b, -c, 0.],
329 [-b, c, 0.],
330 [-b, -c, 0.],
331 [c, 0., b],
332 [c, 0., -b],
333 [-c, 0., b],
334 [-c, 0., -b],
335 ];
336 for v in vs {
337 m.v(v[0] * s, v[1] * s, v[2] * s);
338 }
339 let faces: [[u32; 5]; 12] = [
340 [0, 8, 10, 2, 16],
341 [0, 16, 17, 1, 12],
342 [0, 12, 14, 4, 8],
343 [1, 9, 5, 14, 12],
344 [1, 17, 3, 11, 9],
345 [2, 10, 6, 15, 13],
346 [2, 13, 3, 17, 16],
347 [3, 13, 15, 7, 11],
348 [4, 14, 5, 19, 18],
349 [4, 18, 6, 10, 8],
350 [5, 9, 11, 7, 19],
351 [6, 18, 19, 7, 15],
352 ];
353 for f in faces {
354 m.face(&f);
355 }
356 m
357}
358
359fn uv_sphere(seg: i32, rings: i32) -> Mesh {
362 let mut m = Mesh::default();
363 let seg = seg.clamp(3, 128);
364 let rings = rings.clamp(2, 128);
365 for r in 0..=rings {
366 let v = r as f32 / rings as f32;
367 let theta = v * PI; let (st, ct) = theta.sin_cos();
369 for s in 0..=seg {
370 let u = s as f32 / seg as f32;
371 let phi = u * 2.0 * PI;
372 let (sp, cp) = phi.sin_cos();
373 m.v(st * cp, ct, st * sp);
374 }
375 }
376 let stride = seg + 1;
377 for r in 0..rings {
378 for s in 0..seg {
379 let a = (r * stride + s) as u32;
380 let b = (r * stride + s + 1) as u32;
381 let cc = ((r + 1) * stride + s) as u32;
382 let d = ((r + 1) * stride + s + 1) as u32;
383 m.tri(a, cc, b);
384 m.tri(b, cc, d);
385 }
386 }
387 m.edges_from_tris();
388 m
389}
390
391fn dome(seg: i32, rings: i32) -> Mesh {
392 let mut m = Mesh::default();
394 let seg = seg.clamp(3, 128);
395 let rings = rings.clamp(1, 128);
396 for r in 0..=rings {
397 let v = r as f32 / rings as f32;
398 let theta = v * (PI / 2.0); let (st, ct) = theta.sin_cos();
400 for s in 0..=seg {
401 let phi = s as f32 / seg as f32 * 2.0 * PI;
402 let (sp, cp) = phi.sin_cos();
403 m.v(st * cp, ct, st * sp);
404 }
405 }
406 let stride = seg + 1;
407 for r in 0..rings {
408 for s in 0..seg {
409 let a = (r * stride + s) as u32;
410 let b = (r * stride + s + 1) as u32;
411 let cc = ((r + 1) * stride + s) as u32;
412 let d = ((r + 1) * stride + s + 1) as u32;
413 m.tri(a, cc, b);
414 m.tri(b, cc, d);
415 }
416 }
417 let centre = m.v(0.0, 0.0, 0.0);
419 for s in 0..seg {
420 let a = ((rings) * stride + s) as u32;
421 let b = ((rings) * stride + s + 1) as u32;
422 m.tri(centre, b, a);
423 }
424 m.edges_from_tris();
425 m
426}
427
428fn cylinder(seg: i32) -> Mesh {
429 let mut m = Mesh::default();
430 let seg = seg.clamp(3, 256);
431 for s in 0..seg {
433 let phi = s as f32 / seg as f32 * 2.0 * PI;
434 let (sp, cp) = phi.sin_cos();
435 m.v(cp, -1.0, sp);
436 m.v(cp, 1.0, sp);
437 }
438 for s in 0..seg {
439 let b0 = (2 * s) as u32;
440 let t0 = (2 * s + 1) as u32;
441 let b1 = (2 * ((s + 1) % seg)) as u32;
442 let t1 = (2 * ((s + 1) % seg) + 1) as u32;
443 m.tri(b0, t0, b1);
444 m.tri(b1, t0, t1);
445 m.edge(b0, b1);
446 m.edge(t0, t1);
447 m.edge(b0, t0);
448 }
449 let cb = m.v(0.0, -1.0, 0.0);
450 let ct = m.v(0.0, 1.0, 0.0);
451 for s in 0..seg {
452 let b0 = (2 * s) as u32;
453 let b1 = (2 * ((s + 1) % seg)) as u32;
454 let t0 = (2 * s + 1) as u32;
455 let t1 = (2 * ((s + 1) % seg) + 1) as u32;
456 m.tri(cb, b1, b0);
457 m.tri(ct, t0, t1);
458 }
459 m
460}
461
462fn cone(seg: i32) -> Mesh {
463 let mut m = Mesh::default();
464 let seg = seg.clamp(3, 256);
465 let apex = m.v(0.0, 1.0, 0.0);
466 let base0 = m.verts.len() as u32;
467 for s in 0..seg {
468 let phi = s as f32 / seg as f32 * 2.0 * PI;
469 let (sp, cp) = phi.sin_cos();
470 m.v(cp, -1.0, sp);
471 }
472 let centre = m.v(0.0, -1.0, 0.0);
473 for s in 0..seg {
474 let a = base0 + s as u32;
475 let b = base0 + ((s + 1) % seg) as u32;
476 m.tri(apex, a, b); m.tri(centre, b, a); m.edge(a, b);
479 m.edge(apex, a);
480 }
481 m
482}
483
484fn capsule(seg: i32, rings: i32) -> Mesh {
485 let mut m = Mesh::default();
487 let seg = seg.clamp(3, 128);
488 let rings = rings.clamp(1, 64);
489 let stride = seg + 1;
490 let mut ring_start = Vec::new();
492 let total_rows = 2 * rings; for row in 0..=total_rows {
494 ring_start.push(m.verts.len() as u32);
495 let (cy_off, theta) = if row <= rings {
496 let v = row as f32 / rings as f32;
498 (1.0, v * PI / 2.0)
499 } else {
500 let v = (row - rings) as f32 / rings as f32;
502 (-1.0, PI / 2.0 + v * PI / 2.0)
503 };
504 let (st, ct) = theta.sin_cos();
505 for s in 0..=seg {
506 let phi = s as f32 / seg as f32 * 2.0 * PI;
507 let (sp, cp) = phi.sin_cos();
508 m.v(st * cp, cy_off + ct, st * sp);
509 }
510 }
511 for row in 0..total_rows as usize {
512 for s in 0..seg {
513 let a = ring_start[row] + s as u32;
514 let b = ring_start[row] + s as u32 + 1;
515 let c = ring_start[row + 1] + s as u32;
516 let d = ring_start[row + 1] + s as u32 + 1;
517 m.tri(a, c, b);
518 m.tri(b, c, d);
519 }
520 }
521 let _ = stride;
522 m.edges_from_tris();
523 m
524}
525
526fn torus(seg: i32, sides: i32, tube: f32) -> Mesh {
527 let mut m = Mesh::default();
528 let seg = seg.clamp(3, 256); let sides = sides.clamp(3, 128); let tube = tube.clamp(0.02, 0.9);
531 for i in 0..seg {
532 let u = i as f32 / seg as f32 * 2.0 * PI;
533 let (su, cu) = u.sin_cos();
534 for j in 0..sides {
535 let v = j as f32 / sides as f32 * 2.0 * PI;
536 let (sv, cv) = v.sin_cos();
537 let r = 1.0 - tube + tube * cv;
538 m.v(r * cu, tube * sv, r * su);
539 }
540 }
541 for i in 0..seg {
542 for j in 0..sides {
543 let a = (i * sides + j) as u32;
544 let b = (i * sides + (j + 1) % sides) as u32;
545 let c = (((i + 1) % seg) * sides + j) as u32;
546 let d = (((i + 1) % seg) * sides + (j + 1) % sides) as u32;
547 m.tri(a, c, b);
548 m.tri(b, c, d);
549 }
550 }
551 m.edges_from_tris();
552 m
553}
554
555fn pyramid(sides: i32) -> Mesh {
558 let mut m = Mesh::default();
559 let sides = sides.clamp(3, 128);
560 let apex = m.v(0.0, 1.0, 0.0);
561 let base0 = m.verts.len() as u32;
562 let mut ring = Vec::new();
563 for s in 0..sides {
564 let phi = s as f32 / sides as f32 * 2.0 * PI;
565 let (sp, cp) = phi.sin_cos();
566 ring.push(m.v(cp, -1.0, sp));
567 }
568 for s in 0..sides as usize {
569 let a = ring[s];
570 let b = ring[(s + 1) % sides as usize];
571 m.tri(apex, a, b);
572 m.edge(a, b);
573 m.edge(apex, a);
574 }
575 let mut rev: Vec<u32> = ring.clone();
577 rev.reverse();
578 for k in 1..rev.len() - 1 {
579 m.tri(rev[0], rev[k], rev[k + 1]);
580 }
581 let _ = base0;
582 m
583}
584
585fn prism(sides: i32) -> Mesh {
586 let mut m = Mesh::default();
587 let sides = sides.clamp(3, 128);
588 let mut bot = Vec::new();
589 let mut top = Vec::new();
590 for s in 0..sides {
591 let phi = s as f32 / sides as f32 * 2.0 * PI;
592 let (sp, cp) = phi.sin_cos();
593 bot.push(m.v(cp, -1.0, sp));
594 top.push(m.v(cp, 1.0, sp));
595 }
596 let n = sides as usize;
597 for s in 0..n {
598 let b0 = bot[s];
599 let b1 = bot[(s + 1) % n];
600 let t0 = top[s];
601 let t1 = top[(s + 1) % n];
602 m.tri(b0, t0, b1);
603 m.tri(b1, t0, t1);
604 m.edge(b0, b1);
605 m.edge(t0, t1);
606 m.edge(b0, t0);
607 }
608 for k in 1..n - 1 {
609 m.tri(top[0], top[k], top[k + 1]);
610 }
611 let mut rb: Vec<u32> = bot.clone();
612 rb.reverse();
613 for k in 1..rb.len() - 1 {
614 m.tri(rb[0], rb[k], rb[k + 1]);
615 }
616 m
617}
618
619fn frustum(sides: i32, top_ratio: f32) -> Mesh {
620 let mut m = Mesh::default();
621 let sides = sides.clamp(3, 256);
622 let tr = top_ratio.clamp(0.0, 1.0);
623 let mut bot = Vec::new();
624 let mut top = Vec::new();
625 for s in 0..sides {
626 let phi = s as f32 / sides as f32 * 2.0 * PI;
627 let (sp, cp) = phi.sin_cos();
628 bot.push(m.v(cp, -1.0, sp));
629 top.push(m.v(cp * tr, 1.0, sp * tr));
630 }
631 let n = sides as usize;
632 for s in 0..n {
633 let b0 = bot[s];
634 let b1 = bot[(s + 1) % n];
635 let t0 = top[s];
636 let t1 = top[(s + 1) % n];
637 m.tri(b0, t0, b1);
638 m.tri(b1, t0, t1);
639 m.edge(b0, b1);
640 m.edge(t0, t1);
641 m.edge(b0, t0);
642 }
643 if tr > 0.001 {
644 for k in 1..n - 1 {
645 m.tri(top[0], top[k], top[k + 1]);
646 }
647 }
648 let mut rb: Vec<u32> = bot.clone();
649 rb.reverse();
650 for k in 1..rb.len() - 1 {
651 m.tri(rb[0], rb[k], rb[k + 1]);
652 }
653 m
654}
655
656fn gear(teeth: i32, tooth: f32) -> Mesh {
659 let mut m = Mesh::default();
661 let teeth = teeth.clamp(3, 96);
662 let tooth = tooth.clamp(0.02, 0.6);
663 let pts = teeth * 4; let mut bot = Vec::new();
665 let mut top = Vec::new();
666 for i in 0..pts {
667 let phi = i as f32 / pts as f32 * 2.0 * PI;
668 let phase = (i % 4) as f32;
670 let r = if phase < 2.0 { 1.0 } else { 1.0 - tooth };
671 let (sp, cp) = phi.sin_cos();
672 bot.push(m.v(cp * r, -1.0, sp * r));
673 top.push(m.v(cp * r, 1.0, sp * r));
674 }
675 let n = pts as usize;
676 for s in 0..n {
677 let b0 = bot[s];
678 let b1 = bot[(s + 1) % n];
679 let t0 = top[s];
680 let t1 = top[(s + 1) % n];
681 m.tri(b0, t0, b1);
682 m.tri(b1, t0, t1); m.edge(b0, b1);
684 m.edge(t0, t1);
685 m.edge(b0, t0);
686 }
687 let cb = m.v(0.0, -1.0, 0.0);
688 let ct = m.v(0.0, 1.0, 0.0);
689 for s in 0..n {
690 let b0 = bot[s];
691 let b1 = bot[(s + 1) % n];
692 let t0 = top[s];
693 let t1 = top[(s + 1) % n];
694 m.tri(cb, b1, b0);
695 m.tri(ct, t0, t1); }
697 m
698}
699
700fn gyro(rings: i32) -> Mesh {
701 let mut m = Mesh::default();
703 let rings = rings.clamp(1, 6);
704 for k in 0..rings {
705 let scale = 1.0 - k as f32 * (0.8 / rings as f32);
706 let mut ring = torus(40, 8, 0.06 / scale.max(0.2));
707 let rot = match k % 3 {
709 0 => [0.0, 0.0, 0.0],
710 1 => [PI / 2.0, 0.0, 0.0],
711 _ => [0.0, 0.0, PI / 2.0],
712 };
713 ring.transform([0.0, 0.0, 0.0, scale, scale, scale, rot[0], rot[1], rot[2]]);
714 let base = m.verts.len() as u32;
715 for v in &ring.verts {
716 m.verts.push(*v);
717 }
718 for t in &ring.tris {
719 m.tri(t[0] + base, t[1] + base, t[2] + base);
720 }
721 for e in &ring.edges {
722 m.edge(e[0] + base, e[1] + base);
723 }
724 }
725 m
726}
727
728fn append_mesh(dst: &mut Mesh, src: &Mesh) {
731 let base = dst.verts.len() as u32;
732 for v in &src.verts {
733 dst.verts.push(*v);
734 }
735 for t in &src.tris {
736 dst.tri(t[0] + base, t[1] + base, t[2] + base);
737 }
738 for e in &src.edges {
739 dst.edge(e[0] + base, e[1] + base);
740 }
741}
742
743fn box_between(x0: f32, x1: f32, y0: f32, y1: f32, z0: f32, z1: f32) -> Mesh {
744 let mut m = Mesh::default();
745 let p = [
746 m.v(x0, y0, z0),
747 m.v(x1, y0, z0),
748 m.v(x1, y1, z0),
749 m.v(x0, y1, z0),
750 m.v(x0, y0, z1),
751 m.v(x1, y0, z1),
752 m.v(x1, y1, z1),
753 m.v(x0, y1, z1),
754 ];
755 m.face(&[p[0], p[1], p[2], p[3]]);
756 m.face(&[p[5], p[4], p[7], p[6]]);
757 m.face(&[p[4], p[0], p[3], p[7]]);
758 m.face(&[p[1], p[5], p[6], p[2]]);
759 m.face(&[p[4], p[5], p[1], p[0]]);
760 m.face(&[p[3], p[2], p[6], p[7]]);
761 m
762}
763
764fn helix(turns: i32, tube: f32, sides: i32) -> Mesh {
766 let mut m = Mesh::default();
767 let turns = turns.clamp(1, 24);
768 let sides = sides.clamp(3, 32);
769 let tube = tube.clamp(0.02, 0.5);
770 let seg_per = 24;
771 let total = turns * seg_per;
772 for i in 0..=total {
773 let ang = (i as f32 / seg_per as f32) * 2.0 * PI;
774 let y = -1.0 + 2.0 * (i as f32 / total as f32);
775 let cen = [ang.cos(), y, ang.sin()];
776 let radial = [ang.cos(), 0.0, ang.sin()];
777 let up = [0.0, 1.0, 0.0];
778 for j in 0..sides {
779 let v = j as f32 / sides as f32 * 2.0 * PI;
780 let (sv, cv) = v.sin_cos();
781 m.v(
782 cen[0] + tube * (cv * radial[0] + sv * up[0]),
783 cen[1] + tube * (cv * radial[1] + sv * up[1]),
784 cen[2] + tube * (cv * radial[2] + sv * up[2]),
785 );
786 }
787 }
788 let s = sides;
789 for i in 0..total {
790 for j in 0..sides {
791 let a = (i * s + j) as u32;
792 let b = (i * s + (j + 1) % s) as u32;
793 let c = ((i + 1) * s + j) as u32;
794 let d = ((i + 1) * s + (j + 1) % s) as u32;
795 m.tri(a, c, b);
796 m.tri(b, c, d);
797 }
798 }
799 m.edges_from_tris();
800 m
801}
802
803fn arch(segs: i32, tube: f32) -> Mesh {
805 let mut m = Mesh::default();
806 let segs = segs.clamp(6, 128);
807 let sides = 10i32;
808 let tube = tube.clamp(0.05, 0.4);
809 for i in 0..=segs {
810 let a = PI * (i as f32 / segs as f32); let cen = [a.cos(), a.sin(), 0.0];
812 let radial = [a.cos(), a.sin(), 0.0];
813 let binorm = [0.0, 0.0, 1.0];
814 for j in 0..sides {
815 let v = j as f32 / sides as f32 * 2.0 * PI;
816 let (sv, cv) = v.sin_cos();
817 m.v(
818 cen[0] + tube * (cv * radial[0] + sv * binorm[0]),
819 cen[1] + tube * (cv * radial[1] + sv * binorm[1]),
820 cen[2] + tube * (cv * radial[2] + sv * binorm[2]),
821 );
822 }
823 }
824 for i in 0..segs {
825 for j in 0..sides {
826 let a = (i * sides + j) as u32;
827 let b = (i * sides + (j + 1) % sides) as u32;
828 let c = ((i + 1) * sides + j) as u32;
829 let d = ((i + 1) * sides + (j + 1) % sides) as u32;
830 m.tri(a, c, b);
831 m.tri(b, c, d);
832 }
833 }
834 m.edges_from_tris();
835 m
836}
837
838fn stairs(steps: i32) -> Mesh {
840 let mut m = Mesh::default();
841 let steps = steps.clamp(2, 40);
842 let sh = 2.0 / steps as f32;
843 let sd = 2.0 / steps as f32;
844 for i in 0..steps {
845 let y0 = -1.0 + i as f32 * sh;
846 let y1 = y0 + sh;
847 let z0 = -1.0 + i as f32 * sd;
848 let zf = z0 + sd;
849 let blk = box_between(-1.0, 1.0, y0, y1, z0, zf);
850 append_mesh(&mut m, &blk);
851 }
852 m
853}
854
855fn star_prism(points: i32, inner: f32) -> Mesh {
857 let mut m = Mesh::default();
858 let points = points.clamp(3, 32);
859 let inner = inner.clamp(0.1, 0.95);
860 let n = (points * 2) as usize;
861 let mut bot = Vec::new();
862 let mut top = Vec::new();
863 for k in 0..n {
864 let ang = k as f32 / n as f32 * 2.0 * PI;
865 let r = if k % 2 == 0 { 1.0 } else { inner };
866 let (s, c) = ang.sin_cos();
867 bot.push(m.v(c * r, -1.0, s * r));
868 top.push(m.v(c * r, 1.0, s * r));
869 }
870 for k in 0..n {
871 let b0 = bot[k];
872 let b1 = bot[(k + 1) % n];
873 let t0 = top[k];
874 let t1 = top[(k + 1) % n];
875 m.tri(b0, t0, b1);
876 m.tri(b1, t0, t1);
877 m.edge(b0, b1);
878 m.edge(t0, t1);
879 m.edge(b0, t0);
880 }
881 for k in 1..n - 1 {
882 m.tri(top[0], top[k], top[k + 1]);
883 }
884 let mut rb = bot.clone();
885 rb.reverse();
886 for k in 1..rb.len() - 1 {
887 m.tri(rb[0], rb[k], rb[k + 1]);
888 }
889 m
890}
891
892fn capsule_chain(count: i32) -> Mesh {
894 let mut m = Mesh::default();
895 let count = count.clamp(1, 12);
896 let step = 2.0 / count as f32;
897 for i in 0..count {
898 let mut c = capsule(12, 4);
899 let cx = -1.0 + (i as f32 + 0.5) * step;
900 c.transform([
901 cx,
902 0.0,
903 0.0,
904 step * 0.5,
905 step * 0.5,
906 step * 0.5,
907 0.0,
908 0.0,
909 PI / 2.0,
910 ]);
911 append_mesh(&mut m, &c);
912 }
913 m
914}
915
916fn mobius(segs: i32, width: f32) -> Mesh {
918 let mut m = Mesh::default();
919 let segs = segs.clamp(8, 240);
920 let w = width.clamp(0.05, 0.6);
921 for i in 0..=segs {
922 let u = i as f32 / segs as f32 * 2.0 * PI;
923 for &vv in &[-1.0f32, 1.0] {
924 let v = vv * w;
925 let x = (1.0 + v / 2.0 * (u / 2.0).cos()) * u.cos();
926 let y = v / 2.0 * (u / 2.0).sin();
927 let z = (1.0 + v / 2.0 * (u / 2.0).cos()) * u.sin();
928 m.v(x, y, z);
929 }
930 }
931 for i in 0..segs {
932 let a = (2 * i) as u32;
933 let b = (2 * i + 1) as u32;
934 let c = (2 * (i + 1)) as u32;
935 let d = (2 * (i + 1) + 1) as u32;
936 m.tri(a, c, b);
937 m.tri(b, c, d);
938 }
939 m.edges_from_tris();
940 m
941}
942
943pub fn canon(name: &str) -> Option<&'static str> {
946 Some(match name {
947 "cube" | "box" | "立方体" | "方块" | "箱" | "정육면체" | "상자" | "ลูกบาศก์" | "กล่อง" => {
949 "cube"
950 },
951 "sphere" | "球体" | "球" | "구" | "ทรงกลม" => "sphere",
953 "icosphere" | "二十面球" | "アイコ球" | "아이코구체" | "ทรงกลมเหลี่ยม" => {
955 "icosphere"
956 },
957 "dome" | "穹顶" | "ドーム" | "돔" | "โดม" => "dome",
959 "cylinder" | "圆柱" | "円柱" | "원기둥" | "ทรงกระบอก" => {
961 "cylinder"
962 },
963 "cone" | "圆锥" | "円錐" | "원뿔" | "กรวย" => "cone",
965 "capsule" | "胶囊" | "カプセル" | "캡슐" | "แคปซูล" => "capsule",
967 "torus" | "ring" | "圆环" | "トーラス" | "토러스" | "ทอรัส" => "torus",
969 "pyramid" | "金字塔" | "ピラミッド" | "피라미드" | "พีระมิด" => {
971 "pyramid"
972 },
973 "prism" | "棱柱" | "角柱" | "각기둥" | "ปริซึม" => "prism",
975 "frustum" | "棱台" | "錐台" | "원뿔대" | "กรวยตัด" => "frustum",
977 "tetrahedron" | "d4" | "四面体" | "정사면체" | "ทรงสี่หน้า" => {
979 "tetrahedron"
980 },
981 "octahedron" | "d8" | "八面体" | "정팔면체" | "ทรงแปดหน้า" => {
983 "octahedron"
984 },
985 "dodecahedron" | "d12" | "十二面体" | "정십이면체" | "ทรงสิบสองหน้า" => {
987 "dodecahedron"
988 },
989 "icosahedron" | "d20" | "二十面体" | "정이십면체" | "ทรงยี่สิบหน้า" => {
991 "icosahedron"
992 },
993 "gear" | "cog" | "齿轮" | "歯車" | "톱니바퀴" | "เฟือง" => "gear",
995 "gyro" | "陀螺" | "ジャイロ" | "자이로" | "ไจโร" => "gyro",
997 "helix" | "螺旋线" | "らせん" | "나선" | "เกลียว" => "helix",
999 "spring" | "弹簧" | "ばね" | "스프링" | "สปริง" => "spring",
1001 "arch" | "拱门" | "アーチ" | "아치" | "ซุ้มโค้ง" => "arch",
1003 "stairs" | "楼梯" | "階段" | "계단" | "บันได" => "stairs",
1005 "star_prism" | "star" | "星柱" | "星型柱" | "별기둥" | "แท่งดาว" => {
1007 "star_prism"
1008 },
1009 "capsule_chain" | "chain" | "胶囊链" | "カプセル鎖" | "캡슐체인" | "โซ่แคปซูล" => {
1011 "capsule_chain"
1012 },
1013 "mobius" | "莫比乌斯" | "メビウス" | "뫼비우스" | "เมอบีอุส" => {
1015 "mobius"
1016 },
1017 _ => return None,
1018 })
1019}
1020
1021pub fn build(kind: &str, c: [f32; 9], e0: f32, e1: f32, e2: f32) -> Option<Mesh> {
1024 let mut m = match kind {
1025 "cube" | "box" => cube(),
1026 "sphere" => uv_sphere(iarg(e0, 16), iarg(e1, 12)),
1027 "icosphere" => icosphere(iarg(e0, 1)),
1028 "dome" => dome(iarg(e0, 24), iarg(e1, 8)),
1029 "cylinder" => cylinder(iarg(e0, 24)),
1030 "cone" => cone(iarg(e0, 24)),
1031 "capsule" => capsule(iarg(e0, 16), iarg(e1, 6)),
1032 "torus" | "ring" => torus(iarg(e0, 32), iarg(e1, 12), farg(e2, 0.35)),
1033 "pyramid" => pyramid(iarg(e0, 4)),
1034 "prism" => prism(iarg(e0, 6)),
1035 "frustum" => frustum(iarg(e0, 24), farg(e1, 0.5)),
1036 "tetrahedron" | "d4" => {
1037 let mut t = tetrahedron();
1038 t.edges = vec![];
1039 t.edges_from_tris();
1040 t
1041 },
1042 "octahedron" | "d8" => {
1043 let mut t = octahedron();
1044 t.edges = vec![];
1045 t.edges_from_tris();
1046 t
1047 },
1048 "dodecahedron" | "d12" => dodecahedron(),
1049 "icosahedron" | "d20" => icosahedron(),
1050 "gear" | "cog" => gear(iarg(e0, 12), farg(e1, 0.25)),
1051 "gyro" => gyro(iarg(e0, 3)),
1052 "helix" => helix(iarg(e0, 3), farg(e1, 0.15), iarg(e2, 8)),
1053 "spring" => helix(iarg(e0, 6), farg(e1, 0.12), iarg(e2, 8)),
1054 "arch" => arch(iarg(e0, 24), farg(e1, 0.18)),
1055 "stairs" => stairs(iarg(e0, 5)),
1056 "star_prism" => star_prism(iarg(e0, 5), farg(e1, 0.5)),
1057 "capsule_chain" => capsule_chain(iarg(e0, 3)),
1058 "mobius" => mobius(iarg(e0, 60), farg(e1, 0.3)),
1059 _ => return None,
1060 };
1061 m.transform(c);
1062 m.compute_smooth_normals();
1063 Some(m)
1064}
1065
1066#[derive(Default, Clone)]
1070pub struct ColorMesh {
1071 pub pos: Vec<[f32; 3]>, pub col: Vec<[u8; 3]>, pub height: f32,
1074}
1075
1076impl GfxState {
1077 #[allow(clippy::too_many_arguments)]
1083 pub fn draw_color_mesh(
1084 &mut self,
1085 m: &ColorMesh,
1086 cx: f32,
1087 cy: f32,
1088 cz: f32,
1089 sc: f32,
1090 yaw: f32,
1091 sway: f32,
1092 arm: f32,
1093 lean: f32,
1094 leg: f32,
1095 tuck: f32,
1096 ) {
1097 let near = -self.camera.zdist + 0.05;
1098 let cs = yaw.cos();
1099 let sn = yaw.sin();
1100 let h = m.height.max(1e-4);
1101 let yc = -0.68 * h; let torso = 0.13 * h;
1103 let elbow = torso + 0.16 * h;
1104 let gain = self.mesh_hue_gain;
1107 let hue_on = self.mesh_hue != 0.0 || gain != 1.0;
1108 let (hs, hc) = (self.mesh_hue.sin(), self.mesh_hue.cos());
1109 let k1 = (1.0 - hc) / 3.0;
1110 let k2 = hs * 0.577_350_3;
1111 let (h00, h01, h02) = ((hc + k1) * gain, (k1 - k2) * gain, (k1 + k2) * gain);
1112 let nt = m.col.len();
1113 let mut ti = 0usize;
1114 while ti < nt {
1115 let base = ti * 3;
1116 let mut wv = [[0.0f32; 3]; 3];
1117 let mut k = 0;
1118 while k < 3 {
1119 let p = m.pos[base + k];
1120 let ax = p[0].abs();
1121 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 };
1125 let bw = (((p[1].abs() / h) - 0.40) / 0.45).clamp(0.0, 1.0); let zlean = lean * bw * bw * h - lean * aw * 0.6 * h;
1132 let lw = (((0.45 * h - p[1].abs()) / (0.45 * h)).clamp(0.0, 1.0)) * (1.0 - aw);
1135 let fw = (((0.16 * h - p[1].abs()) / (0.16 * h)).clamp(0.0, 1.0)) * (1.0 - aw);
1136 let legswing = leg * side * lw;
1137 let mut ylift = 0.0f32;
1138 if legswing > 0.0 {
1139 ylift -= legswing * fw * 0.45 * h;
1140 } ylift -= tuck * lw * 0.22 * h; let xs = p[0] + sway * p[1].abs();
1143 let zs =
1144 p[2] + arm * side * (aw + ew * 0.7) + zlean + legswing + tuck * lw * 0.16 * h;
1145 wv[k] = [
1146 cx + (xs * cs + zs * sn) * sc,
1147 cy + (p[1] + ylift) * sc,
1148 cz + (zs * cs - xs * sn) * sc,
1149 ];
1150 k += 1;
1151 }
1152 let a = wv[0];
1153 let b = wv[1];
1154 let c = wv[2];
1155 let da = self.camera.depth(a[0], a[1], a[2]);
1156 let db = self.camera.depth(b[0], b[1], b[2]);
1157 let dc = self.camera.depth(c[0], c[1], c[2]);
1158 if !(da <= near && db <= near && dc <= near) {
1159 let vin = [(a, da), (b, db), (c, dc)];
1161 let mut clip: [[f32; 3]; 4] = [[0.0; 3]; 4];
1162 let mut cn = 0usize;
1163 let mut i = 0;
1164 while i < 3 {
1165 let (pa, pad) = vin[i];
1166 let (pb, pbd) = vin[(i + 1) % 3];
1167 let ain = pad > near;
1168 let bin = pbd > near;
1169 if ain && cn < 4 {
1170 clip[cn] = pa;
1171 cn += 1;
1172 }
1173 if ain != bin && cn < 4 {
1174 let t = (near - pad) / (pbd - pad);
1175 clip[cn] = [
1176 pa[0] + (pb[0] - pa[0]) * t,
1177 pa[1] + (pb[1] - pa[1]) * t,
1178 pa[2] + (pb[2] - pa[2]) * t,
1179 ];
1180 cn += 1;
1181 }
1182 i += 1;
1183 }
1184 if cn >= 3 {
1185 let col = m.col[ti];
1186 let packed = if hue_on {
1187 let (r, g, b) = (col[0] as f32, col[1] as f32, col[2] as f32);
1188 let hr = (r * h00 + g * h01 + b * h02).clamp(0.0, 255.0) as u32;
1189 let hg = (r * h02 + g * h00 + b * h01).clamp(0.0, 255.0) as u32;
1190 let hb = (r * h01 + g * h02 + b * h00).clamp(0.0, 255.0) as u32;
1191 (hr << 16) | (hg << 8) | hb
1192 } else {
1193 ((col[0] as u32) << 16) | ((col[1] as u32) << 8) | (col[2] as u32)
1194 };
1195 let mut proj: [(f32, f32, f32); 4] = [(0.0, 0.0, 0.0); 4];
1196 let mut depth = 0.0f32;
1197 let mut pi = 0;
1198 while pi < cn {
1199 proj[pi] = self.camera.project(clip[pi][0], clip[pi][1], clip[pi][2]);
1200 depth += proj[pi].2;
1201 pi += 1;
1202 }
1203 depth /= cn as f32;
1204 let mut j = 1;
1205 while j + 1 < cn {
1206 self.depth_queue.push_triangle(
1207 depth,
1208 packed,
1209 proj[0].0,
1210 proj[0].1,
1211 proj[j].0,
1212 proj[j].1,
1213 proj[j + 1].0,
1214 proj[j + 1].1,
1215 );
1216 j += 1;
1217 }
1218 }
1219 }
1220 ti += 1;
1221 }
1222 }
1223
1224 pub fn distort(&mut self, amount: f32, t: f32, step: usize) {
1229 let w = self.width;
1230 let h = self.height;
1231 if w < 2 || h < 2 || amount <= 0.0 {
1232 return;
1233 }
1234 let step = step.max(1);
1235 if self.distort_buf.len() != w * h {
1242 self.distort_buf.clear();
1243 self.distort_buf.resize(w * h, 0);
1244 }
1245 let mut src = std::mem::take(&mut self.distort_buf);
1246 std::mem::swap(&mut self.buffer, &mut src);
1247 let a = amount;
1248 let mut rdx = vec![0i32; h];
1250 let mut rdy = vec![0i32; h];
1251 for y in 0..h {
1252 let fy = y as f32;
1253 rdx[y] =
1254 ((fy * 0.018 + t * 0.8).sin() * a + (fy * 0.005 - t * 0.5).sin() * a * 0.6) as i32;
1255 rdy[y] = ((fy * 0.040 + t * 1.1).sin() * a * 0.4) as i32;
1256 }
1257 let mut cdy = vec![0i32; w];
1260 let mut cdx = vec![0i32; w];
1261 for x in 0..w {
1262 let fx = x as f32;
1263 cdy[x] =
1264 ((fx * 0.020 + t * 0.7).sin() * a + (fx * 0.006 + t * 0.45).sin() * a * 0.6) as i32;
1265 cdx[x] = ((fx * 0.050 + t * 0.9).sin() * a * 0.4) as i32;
1266 }
1267 let wi = w as i32;
1268 let hi = h as i32;
1269 if step == 1 {
1270 let warp_row = |y: usize, out: &mut [u32]| {
1273 let rdx_y = rdx[y];
1274 let ry = rdy[y];
1275 for x in 0..w {
1276 let mut sxi = x as i32 + rdx_y + cdx[x];
1278 if sxi < 0 {
1279 sxi += wi;
1280 } else if sxi >= wi {
1281 sxi -= wi;
1282 }
1283 let mut syi = y as i32 + cdy[x] + ry;
1284 if syi < 0 {
1285 syi += hi;
1286 } else if syi >= hi {
1287 syi -= hi;
1288 }
1289 out[x] = src[syi as usize * w + sxi as usize];
1290 }
1291 };
1292 #[cfg(not(target_arch = "wasm32"))]
1293 {
1294 use rayon::prelude::*;
1295 self.buffer
1296 .par_chunks_mut(w)
1297 .enumerate()
1298 .for_each(|(y, out)| warp_row(y, out));
1299 }
1300 #[cfg(target_arch = "wasm32")]
1301 for (y, out) in self.buffer.chunks_mut(w).enumerate() {
1302 warp_row(y, out);
1303 }
1304 } else {
1305 let mut by = 0;
1312 while by < h {
1313 let yend = (by + step).min(h);
1314 let mut bx = 0;
1315 while bx < w {
1316 let xend = (bx + step).min(w);
1317 let mut sxi = bx as i32 + rdx[by] + cdx[bx];
1318 if sxi < 0 {
1319 sxi += wi;
1320 } else if sxi >= wi {
1321 sxi -= wi;
1322 }
1323 let mut syi = by as i32 + cdy[bx] + rdy[by];
1324 if syi < 0 {
1325 syi += hi;
1326 } else if syi >= hi {
1327 syi -= hi;
1328 }
1329 let pix = src[syi as usize * w + sxi as usize];
1330 for y in by..yend {
1331 let row = y * w;
1332 for x in bx..xend {
1333 self.buffer[row + x] = pix;
1334 }
1335 }
1336 bx += step;
1337 }
1338 by += step;
1339 }
1340 }
1341 self.distort_buf = src; }
1343
1344 pub fn emit_mesh(&mut self, m: &Mesh, mode: i32) {
1347 let near = -self.camera.zdist + 0.05;
1348
1349 let want_fill = mode == 0 || mode == 2;
1350 if want_fill {
1351 let have_normals = m.normals.len() == m.verts.len() && self.shade_mode != 0;
1352 if have_normals {
1353 let base = ling_graphics::shading::unpack(self.color);
1357 let eye = [self.camera.tx, self.camera.ty, self.camera.tz];
1358 let lights: Vec<ling_graphics::shading::LightS> = self
1359 .lights
1360 .iter()
1361 .map(|l| ling_graphics::shading::LightS {
1362 pos: [l.x, l.y, l.z],
1363 color: [l.r, l.g, l.b],
1364 intensity: l.intensity,
1365 radius: l.radius,
1366 })
1367 .collect();
1368 let mut sp = self.shade;
1369 sp.ambient = self.ambient; if self.shade_mode == 1 {
1371 sp.holo = false;
1372 sp.rim *= 0.4;
1373 }
1374 let bands = sp.bands;
1375 for t in &m.tris {
1376 let ia = t[0] as usize;
1377 let ib = t[1] as usize;
1378 let ic = t[2] as usize;
1379 let a = m.verts[ia];
1380 let b = m.verts[ib];
1381 let c = m.verts[ic];
1382 let da = self.camera.depth(a[0], a[1], a[2]);
1383 let db = self.camera.depth(b[0], b[1], b[2]);
1384 let dc = self.camera.depth(c[0], c[1], c[2]);
1385 if da <= near && db <= near && dc <= near {
1386 continue;
1387 } let la = ling_graphics::shading::lit_vertex(
1390 base,
1391 m.normals[ia],
1392 a,
1393 eye,
1394 &lights,
1395 &sp,
1396 );
1397 let lb = ling_graphics::shading::lit_vertex(
1398 base,
1399 m.normals[ib],
1400 b,
1401 eye,
1402 &lights,
1403 &sp,
1404 );
1405 let lc = ling_graphics::shading::lit_vertex(
1406 base,
1407 m.normals[ic],
1408 c,
1409 eye,
1410 &lights,
1411 &sp,
1412 );
1413 let poly = near_clip_poly(&[(a, la, da), (b, lb, db), (c, lc, dc)], near);
1415 if poly.len() < 3 {
1416 continue;
1417 }
1418 let proj: Vec<(f32, f32, f32, u32)> = poly
1419 .iter()
1420 .map(|(p, col)| {
1421 let (sx, sy, pz) = self.camera.project(p[0], p[1], p[2]);
1422 (sx, sy, pz, ling_graphics::shading::pack(*col))
1423 })
1424 .collect();
1425 let mut k = 1;
1426 while k + 1 < proj.len() {
1427 self.depth_queue.push_triangle_g_zv(
1428 proj[0].0,
1429 proj[0].1,
1430 proj[0].2,
1431 proj[0].3,
1432 proj[k].0,
1433 proj[k].1,
1434 proj[k].2,
1435 proj[k].3,
1436 proj[k + 1].0,
1437 proj[k + 1].1,
1438 proj[k + 1].2,
1439 proj[k + 1].3,
1440 bands,
1441 false,
1442 );
1443 k += 1;
1444 }
1445 }
1446 } else {
1447 for t in &m.tris {
1449 let a = m.verts[t[0] as usize];
1450 let b = m.verts[t[1] as usize];
1451 let c = m.verts[t[2] as usize];
1452 let ux = b[0] - a[0];
1453 let uy = b[1] - a[1];
1454 let uz = b[2] - a[2];
1455 let vx = c[0] - a[0];
1456 let vy = c[1] - a[1];
1457 let vz = c[2] - a[2];
1458 let normal = [uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx];
1459 let centroid = [
1460 (a[0] + b[0] + c[0]) / 3.0,
1461 (a[1] + b[1] + c[1]) / 3.0,
1462 (a[2] + b[2] + c[2]) / 3.0,
1463 ];
1464 let lit = if self.flat_shade {
1465 self.color
1466 } else {
1467 crate::gfx::light::compute_lit_color(
1468 self.color,
1469 normal,
1470 centroid,
1471 &self.lights,
1472 self.ambient,
1473 )
1474 };
1475 let da = self.camera.depth(a[0], a[1], a[2]);
1476 let db = self.camera.depth(b[0], b[1], b[2]);
1477 let dc = self.camera.depth(c[0], c[1], c[2]);
1478 if da <= near && db <= near && dc <= near {
1479 continue;
1480 } let poly = near_clip_poly(
1483 &[(a, [0.0; 3], da), (b, [0.0; 3], db), (c, [0.0; 3], dc)],
1484 near,
1485 );
1486 if poly.len() < 3 {
1487 continue;
1488 }
1489 let proj: Vec<(f32, f32, f32)> = poly
1490 .iter()
1491 .map(|(p, _)| self.camera.project(p[0], p[1], p[2]))
1492 .collect();
1493 let mut k = 1;
1494 while k + 1 < proj.len() {
1495 self.depth_queue.push_triangle_zv(
1496 lit,
1497 proj[0].0,
1498 proj[0].1,
1499 proj[0].2,
1500 proj[k].0,
1501 proj[k].1,
1502 proj[k].2,
1503 proj[k + 1].0,
1504 proj[k + 1].1,
1505 proj[k + 1].2,
1506 );
1507 k += 1;
1508 }
1509 }
1510 }
1511 }
1512
1513 if mode == 1 || mode == 2 {
1514 let color = self.color;
1515 let bias = if mode == 2 { 0.03 } else { 0.0 };
1517 for e in &m.edges {
1518 let mut a = m.verts[e[0] as usize];
1519 let mut b = m.verts[e[1] as usize];
1520 let da = self.camera.depth(a[0], a[1], a[2]);
1521 let db = self.camera.depth(b[0], b[1], b[2]);
1522 if da <= near && db <= near {
1523 continue;
1524 }
1525 if da <= near {
1526 let t = (near - da) / (db - da);
1527 a = [
1528 a[0] + t * (b[0] - a[0]),
1529 a[1] + t * (b[1] - a[1]),
1530 a[2] + t * (b[2] - a[2]),
1531 ];
1532 } else if db <= near {
1533 let t = (near - da) / (db - da);
1534 b = [
1535 a[0] + t * (b[0] - a[0]),
1536 a[1] + t * (b[1] - a[1]),
1537 a[2] + t * (b[2] - a[2]),
1538 ];
1539 }
1540 let (sax, say, pa) = self.camera.project(a[0], a[1], a[2]);
1541 let (sbx, sby, pb) = self.camera.project(b[0], b[1], b[2]);
1542 let depth = (pa + pb) / 2.0 - bias;
1543 self.depth_queue.push_line(depth, color, sax, say, sbx, sby);
1544 }
1545 }
1546 }
1547
1548 fn fog_intensity(&self, x: f32, y: f32, z: f32, intensity: f32) -> f32 {
1552 if self.fog_end <= 0.0 {
1553 return intensity;
1554 }
1555 let span = self.fog_end - self.fog_start;
1556 if span <= 0.0 {
1557 return intensity;
1558 }
1559 let d = self.camera.depth(x, y, z);
1560 let f = ((d - self.fog_start) / span).clamp(0.0, 1.0);
1561 intensity * (1.0 - f)
1562 }
1563
1564 fn emit_grad_tri_world(&mut self, v: [([f32; 3], [f32; 3]); 3]) {
1568 let near = -self.camera.zdist + 0.05;
1569 let d0 = self.camera.depth(v[0].0[0], v[0].0[1], v[0].0[2]);
1570 let d1 = self.camera.depth(v[1].0[0], v[1].0[1], v[1].0[2]);
1571 let d2 = self.camera.depth(v[2].0[0], v[2].0[1], v[2].0[2]);
1572 if d0 <= near && d1 <= near && d2 <= near {
1573 return;
1574 }
1575 let poly = near_clip_poly(
1576 &[
1577 (v[0].0, v[0].1, d0),
1578 (v[1].0, v[1].1, d1),
1579 (v[2].0, v[2].1, d2),
1580 ],
1581 near,
1582 );
1583 if poly.len() < 3 {
1584 return;
1585 }
1586 let proj: Vec<(f32, f32, f32, u32)> = poly
1587 .iter()
1588 .map(|(p, col)| {
1589 let (sx, sy, pz) = self.camera.project(p[0], p[1], p[2]);
1590 (sx, sy, pz, ling_graphics::shading::pack(*col))
1591 })
1592 .collect();
1593 let mut k = 1;
1594 while k + 1 < proj.len() {
1595 self.depth_queue.push_triangle_g_zv(
1596 proj[0].0,
1597 proj[0].1,
1598 proj[0].2,
1599 proj[0].3,
1600 proj[k].0,
1601 proj[k].1,
1602 proj[k].2,
1603 proj[k].3,
1604 proj[k + 1].0,
1605 proj[k + 1].1,
1606 proj[k + 1].2,
1607 proj[k + 1].3,
1608 0,
1609 false, );
1611 k += 1;
1612 }
1613 }
1614
1615 pub fn emit_light_pool(
1621 &mut self,
1622 x: f32,
1623 y: f32,
1624 z: f32,
1625 radius: f32,
1626 col: [f32; 3],
1627 intensity: f32,
1628 ) {
1629 let inten = self.fog_intensity(x, y, z, intensity);
1630 if inten <= 0.004 || radius <= 0.01 {
1631 return;
1632 }
1633 let y = y - 0.22; let cc = [
1635 (col[0] * inten).min(1.0),
1636 (col[1] * inten).min(1.0),
1637 (col[2] * inten).min(1.0),
1638 ];
1639 let cm = [cc[0] * 0.35, cc[1] * 0.35, cc[2] * 0.35];
1640 const ZERO: [f32; 3] = [0.0, 0.0, 0.0];
1641 const SEG: usize = 20;
1642 const TAU: f32 = std::f32::consts::TAU;
1643 let rm = radius * 0.5;
1644 self.depth_queue.set_state(1, 1.0);
1646 for s in 0..SEG {
1647 let a0 = s as f32 / SEG as f32 * TAU;
1648 let a1 = (s + 1) as f32 / SEG as f32 * TAU;
1649 let (c0, s0) = (a0.cos(), a0.sin());
1650 let (c1, s1) = (a1.cos(), a1.sin());
1651 let m0 = [x + c0 * rm, y, z + s0 * rm];
1652 let m1 = [x + c1 * rm, y, z + s1 * rm];
1653 let o0 = [x + c0 * radius, y, z + s0 * radius];
1654 let o1 = [x + c1 * radius, y, z + s1 * radius];
1655 self.emit_grad_tri_world([([x, y, z], cc), (m0, cm), (m1, cm)]);
1656 self.emit_grad_tri_world([(m0, cm), (o0, ZERO), (o1, ZERO)]);
1657 self.emit_grad_tri_world([(m0, cm), (o1, ZERO), (m1, cm)]);
1658 }
1659 self.depth_queue.set_state(self.blend, self.alpha);
1660 }
1661
1662 pub fn emit_light_beam(
1668 &mut self,
1669 x: f32,
1670 y: f32,
1671 z: f32,
1672 fy: f32,
1673 radius: f32,
1674 col: [f32; 3],
1675 intensity: f32,
1676 ) {
1677 let inten = self.fog_intensity(x, y, z, intensity);
1678 if inten <= 0.004 || radius <= 0.01 {
1679 return;
1680 }
1681 let apex = [x, y, z];
1682 let ca = [
1683 (col[0] * inten * 0.85).min(1.0),
1684 (col[1] * inten * 0.85).min(1.0),
1685 (col[2] * inten * 0.85).min(1.0),
1686 ];
1687 let cb = [ca[0] * 0.20, ca[1] * 0.20, ca[2] * 0.20];
1688 const ZERO: [f32; 3] = [0.0, 0.0, 0.0];
1689 const SEG: usize = 14;
1690 const TAU: f32 = std::f32::consts::TAU;
1691 let fy = fy - 0.20; let rc = radius * 0.45;
1693 self.depth_queue.set_state(1, 1.0);
1694 for s in 0..SEG {
1695 let a0 = s as f32 / SEG as f32 * TAU;
1696 let a1 = (s + 1) as f32 / SEG as f32 * TAU;
1697 let (c0, s0) = (a0.cos(), a0.sin());
1698 let (c1, s1) = (a1.cos(), a1.sin());
1699 let o0 = [x + c0 * radius, fy, z + s0 * radius];
1701 let o1 = [x + c1 * radius, fy, z + s1 * radius];
1702 self.emit_grad_tri_world([(apex, ca), (o0, ZERO), (o1, ZERO)]);
1703 let i0 = [x + c0 * rc, fy, z + s0 * rc];
1705 let i1 = [x + c1 * rc, fy, z + s1 * rc];
1706 self.emit_grad_tri_world([(apex, ca), (i0, cb), (i1, cb)]);
1707 }
1708 self.depth_queue.set_state(self.blend, self.alpha);
1709 }
1710}
1711
1712fn near_clip_poly(vin: &[([f32; 3], [f32; 3], f32)], near: f32) -> Vec<([f32; 3], [f32; 3])> {
1718 let n = vin.len();
1719 let mut out: Vec<([f32; 3], [f32; 3])> = Vec::with_capacity(n + 1);
1720 for i in 0..n {
1721 let a = &vin[i];
1722 let b = &vin[(i + 1) % n];
1723 let ain = a.2 > near;
1724 let bin = b.2 > near;
1725 if ain {
1726 out.push((a.0, a.1));
1727 }
1728 if ain != bin {
1729 let t = (near - a.2) / (b.2 - a.2);
1730 let lerp3 = |p: [f32; 3], q: [f32; 3]| {
1731 [
1732 p[0] + (q[0] - p[0]) * t,
1733 p[1] + (q[1] - p[1]) * t,
1734 p[2] + (q[2] - p[2]) * t,
1735 ]
1736 };
1737 out.push((lerp3(a.0, b.0), lerp3(a.1, b.1)));
1738 }
1739 }
1740 out
1741}