1use std::collections::HashSet;
14
15#[inline]
19fn canonical(a: u64, b: u64) -> (u64, u64) {
20 if a <= b {
21 (a, b)
22 } else {
23 (b, a)
24 }
25}
26
27#[inline]
31pub fn world_id(x: f32, y: f32, z: f32) -> u64 {
32 let xi = (x * 64.0).round() as i16;
33 let yi = (y * 64.0).round() as i16;
34 let zi = (z * 64.0).round() as i16;
35 ((xi as u16 as u64) << 32) | ((yi as u16 as u64) << 16) | (zi as u16 as u64)
36}
37
38pub struct EdgeSet {
40 set: HashSet<(u64, u64)>,
41}
42
43impl Default for EdgeSet {
44 fn default() -> Self {
45 Self { set: HashSet::with_capacity(1024) }
46 }
47}
48
49impl EdgeSet {
50 #[inline]
53 pub fn try_insert(&mut self, x0: f32, y0: f32, z0: f32, x1: f32, y1: f32, z1: f32) -> bool {
54 let a = world_id(x0, y0, z0);
55 let b = world_id(x1, y1, z1);
56 self.set.insert(canonical(a, b))
57 }
58
59 #[inline]
60 pub fn clear(&mut self) {
61 self.set.clear();
62 }
63}
64
65#[inline]
75pub fn fan_emit_3d<F>(xs: &[f32], ys: &[f32], zs: &[f32], cs: &[u32], n: usize, mut emit: F)
76where
77 F: FnMut(f32, f32, f32, u32, f32, f32, f32, u32, f32, f32, f32, u32),
78{
79 if n < 3 {
80 return;
81 }
82 let ax = xs[0];
83 let ay = ys[0];
84 let az = zs[0];
85 let ac = cs[0];
86 for i in 1..n - 1 {
87 emit(
88 ax,
89 ay,
90 az,
91 ac,
92 xs[i],
93 ys[i],
94 zs[i],
95 cs[i],
96 xs[i + 1],
97 ys[i + 1],
98 zs[i + 1],
99 cs[i + 1],
100 );
101 }
102}
103
104#[inline]
111pub fn fan_emit_proj<F>(poly: &[(f32, f32, f32, u32)], n: usize, mut emit: F)
112where
113 F: FnMut(f32, f32, f32, u32, f32, f32, f32, u32, f32, f32, f32, u32),
114{
115 if n < 3 {
116 return;
117 }
118 let (ax, ay, az, ac) = poly[0];
119 for i in 1..n - 1 {
120 let (bx, by, bz, bc) = poly[i];
121 let (cx, cy, cz, cc) = poly[i + 1];
122 emit(ax, ay, az, ac, bx, by, bz, bc, cx, cy, cz, cc);
123 }
124}
125
126pub const MAX_CLIP_VERTS: usize = 9; #[allow(clippy::too_many_arguments)]
137pub fn clip_near(
138 input: &[(f32, f32, f32, f32, u32)], n_in: usize,
140 near: f32,
141 output: &mut [(f32, f32, f32, f32, u32); MAX_CLIP_VERTS],
142) -> usize {
143 let mut n_out = 0usize;
144 for ei in 0..n_in {
145 let a = input[ei];
146 let b = input[(ei + 1) % n_in];
147 let a_in = a.3 > near;
148 let b_in = b.3 > near;
149 if a_in && n_out < MAX_CLIP_VERTS {
150 output[n_out] = a;
151 n_out += 1;
152 }
153 if a_in != b_in && n_out < MAX_CLIP_VERTS {
154 let t = (near - a.3) / (b.3 - a.3);
155 output[n_out] = (
156 a.0 + (b.0 - a.0) * t,
157 a.1 + (b.1 - a.1) * t,
158 a.2 + (b.2 - a.2) * t,
159 near,
160 lerp_color(a.4, b.4, t),
161 );
162 n_out += 1;
163 }
164 }
165 n_out
166}
167
168#[inline]
170pub fn lerp_color(a: u32, b: u32, t: f32) -> u32 {
171 let ar = ((a >> 16) & 0xFF) as f32;
172 let ag = ((a >> 8) & 0xFF) as f32;
173 let ab = (a & 0xFF) as f32;
174 let br = ((b >> 16) & 0xFF) as f32;
175 let bg = ((b >> 8) & 0xFF) as f32;
176 let bb = (b & 0xFF) as f32;
177 let r = (ar + (br - ar) * t).clamp(0.0, 255.0) as u32;
178 let g = (ag + (bg - ag) * t).clamp(0.0, 255.0) as u32;
179 let bl = (ab + (bb - ab) * t).clamp(0.0, 255.0) as u32;
180 (r << 16) | (g << 8) | bl
181}
182
183#[inline]
187#[allow(clippy::too_many_arguments)]
188pub fn face_normal(
189 ax: f32,
190 ay: f32,
191 az: f32,
192 bx: f32,
193 by: f32,
194 bz: f32,
195 cx: f32,
196 cy: f32,
197 cz: f32,
198) -> [f32; 3] {
199 let ux = bx - ax;
200 let uy = by - ay;
201 let uz = bz - az;
202 let vx = cx - ax;
203 let vy = cy - ay;
204 let vz = cz - az;
205 [uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx]
206}