1use std::collections::HashSet;
14
15#[inline]
19fn canonical(a: u64, b: u64) -> (u64, u64) {
20 if a <= b { (a, b) } else { (b, a) }
21}
22
23#[inline]
27pub fn world_id(x: f32, y: f32, z: f32) -> u64 {
28 let xi = (x * 64.0).round() as i16;
29 let yi = (y * 64.0).round() as i16;
30 let zi = (z * 64.0).round() as i16;
31 ((xi as u16 as u64) << 32) | ((yi as u16 as u64) << 16) | (zi as u16 as u64)
32}
33
34pub struct EdgeSet {
36 set: HashSet<(u64, u64)>,
37}
38
39impl Default for EdgeSet {
40 fn default() -> Self {
41 Self { set: HashSet::with_capacity(1024) }
42 }
43}
44
45impl EdgeSet {
46 #[inline]
49 pub fn try_insert(&mut self, x0: f32, y0: f32, z0: f32, x1: f32, y1: f32, z1: f32) -> bool {
50 let a = world_id(x0, y0, z0);
51 let b = world_id(x1, y1, z1);
52 self.set.insert(canonical(a, b))
53 }
54
55 #[inline]
56 pub fn clear(&mut self) {
57 self.set.clear();
58 }
59}
60
61#[inline]
71pub fn fan_emit_3d<F>(
72 xs: &[f32],
73 ys: &[f32],
74 zs: &[f32],
75 cs: &[u32],
76 n: usize,
77 mut emit: F,
78)
79where
80 F: FnMut(f32, f32, f32, u32, f32, f32, f32, u32, f32, f32, f32, u32),
81{
82 if n < 3 {
83 return;
84 }
85 let ax = xs[0]; let ay = ys[0]; let az = zs[0]; let ac = cs[0];
86 for i in 1..n - 1 {
87 emit(
88 ax, ay, az, ac,
89 xs[i], ys[i], zs[i], cs[i],
90 xs[i + 1], ys[i + 1], zs[i + 1], cs[i + 1],
91 );
92 }
93}
94
95#[inline]
102pub fn fan_emit_proj<F>(poly: &[(f32, f32, f32, u32)], n: usize, mut emit: F)
103where
104 F: FnMut(f32, f32, f32, u32, f32, f32, f32, u32, f32, f32, f32, u32),
105{
106 if n < 3 {
107 return;
108 }
109 let (ax, ay, az, ac) = poly[0];
110 for i in 1..n - 1 {
111 let (bx, by, bz, bc) = poly[i];
112 let (cx, cy, cz, cc) = poly[i + 1];
113 emit(ax, ay, az, ac, bx, by, bz, bc, cx, cy, cz, cc);
114 }
115}
116
117pub const MAX_CLIP_VERTS: usize = 9; #[allow(clippy::too_many_arguments)]
128pub fn clip_near(
129 input: &[(f32, f32, f32, f32, u32)], n_in: usize,
131 near: f32,
132 output: &mut [(f32, f32, f32, f32, u32); MAX_CLIP_VERTS],
133) -> usize {
134 let mut n_out = 0usize;
135 for ei in 0..n_in {
136 let a = input[ei];
137 let b = input[(ei + 1) % n_in];
138 let a_in = a.3 > near;
139 let b_in = b.3 > near;
140 if a_in && n_out < MAX_CLIP_VERTS {
141 output[n_out] = a;
142 n_out += 1;
143 }
144 if a_in != b_in && n_out < MAX_CLIP_VERTS {
145 let t = (near - a.3) / (b.3 - a.3);
146 output[n_out] = (
147 a.0 + (b.0 - a.0) * t,
148 a.1 + (b.1 - a.1) * t,
149 a.2 + (b.2 - a.2) * t,
150 near,
151 lerp_color(a.4, b.4, t),
152 );
153 n_out += 1;
154 }
155 }
156 n_out
157}
158
159#[inline]
161pub fn lerp_color(a: u32, b: u32, t: f32) -> u32 {
162 let ar = ((a >> 16) & 0xFF) as f32;
163 let ag = ((a >> 8) & 0xFF) as f32;
164 let ab = (a & 0xFF) as f32;
165 let br = ((b >> 16) & 0xFF) as f32;
166 let bg = ((b >> 8) & 0xFF) as f32;
167 let bb = (b & 0xFF) as f32;
168 let r = (ar + (br - ar) * t).clamp(0.0, 255.0) as u32;
169 let g = (ag + (bg - ag) * t).clamp(0.0, 255.0) as u32;
170 let bl = (ab + (bb - ab) * t).clamp(0.0, 255.0) as u32;
171 (r << 16) | (g << 8) | bl
172}
173
174#[inline]
178pub fn face_normal(
179 ax: f32, ay: f32, az: f32,
180 bx: f32, by: f32, bz: f32,
181 cx: f32, cy: f32, cz: f32,
182) -> [f32; 3] {
183 let ux = bx - ax; let uy = by - ay; let uz = bz - az;
184 let vx = cx - ax; let vy = cy - ay; let vz = cz - az;
185 [uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx]
186}