1use rayon::prelude::*;
6
7use crate::{Lines, PIXEL_SHIFT, PIXEL_WIDTH};
8
9mod grouped_iter;
10mod pixel_segment;
11
12use grouped_iter::GroupedIter;
13pub use pixel_segment::{bit_field_lens, search_last_by_key, PixelSegment, PixelSegmentUnpacked};
14
15fn find(i: i32, sum_recip: f32, cd: f32, a: f32, b: f32, c: f32, d: f32) -> f32 {
25 const BIAS: f32 = -0.000_000_5;
26
27 let i = i as f32;
28
29 let ja = if b.is_finite() { (b.mul_add(i, -cd).mul_add(sum_recip, BIAS)).ceil() } else { i };
30 let jb = if a.is_finite() { (a.mul_add(i, cd).mul_add(sum_recip, BIAS)).ceil() } else { i };
31
32 let guess_a = a.mul_add(ja, c);
33 let guess_b = b.mul_add(jb, d);
34
35 guess_a.min(guess_b)
36}
37
38fn round(v: f32) -> i32 {
39 unsafe { (v + 0.5).floor().to_int_unchecked() }
40}
41
42#[derive(Debug, Default)]
43pub struct Rasterizer<const TW: usize, const TH: usize> {
44 segments: Vec<PixelSegment<TW, TH>>,
45}
46
47impl<const TW: usize, const TH: usize> Rasterizer<TW, TH> {
48 pub fn new() -> Self {
49 Self::default()
50 }
51
52 pub fn segments(&self) -> &[PixelSegment<TW, TH>] {
53 self.segments.as_slice()
54 }
55
56 #[inline(never)]
57 pub fn rasterize(&mut self, lines: &Lines) {
58 let iter = GroupedIter::new(&lines.lengths);
60
61 iter.into_par_iter()
62 .with_min_len(256)
63 .map(|(li, pi)| {
64 let a = lines.a[li as usize];
65 let b = lines.b[li as usize];
66 let c = lines.c[li as usize];
67 let d = lines.d[li as usize];
68
69 let i = pi as i32 - i32::from(c != 0.0) - i32::from(d != 0.0);
70
71 let i0 = i;
72 let i1 = i + 1;
73
74 let sum_recip = (a + b).recip();
75 let cd = c - d;
76
77 let t0 = find(i0, sum_recip, cd, a, b, c, d).max(0.0);
78 let t1 = find(i1, sum_recip, cd, a, b, c, d).min(1.0);
79
80 let x0f = t0.mul_add(lines.dx[li as usize], lines.x0[li as usize]);
81 let y0f = t0.mul_add(lines.dy[li as usize], lines.y0[li as usize]);
82 let x1f = t1.mul_add(lines.dx[li as usize], lines.x0[li as usize]);
83 let y1f = t1.mul_add(lines.dy[li as usize], lines.y0[li as usize]);
84
85 let x0_sub = round(x0f);
86 let x1_sub = round(x1f);
87 let y0_sub = round(y0f);
88 let y1_sub = round(y1f);
89
90 let border_x = x0_sub.min(x1_sub) >> PIXEL_SHIFT;
91 let border_y = y0_sub.min(y1_sub) >> PIXEL_SHIFT;
92
93 let tile_x = (border_x >> TW.trailing_zeros() as i32) as i16;
94 let tile_y = (border_y >> TH.trailing_zeros() as i32) as i16;
95 let local_x = (border_x & (TW - 1) as i32) as u8;
96 let local_y = (border_y & (TH - 1) as i32) as u8;
97
98 let border = (border_x << PIXEL_SHIFT) + PIXEL_WIDTH as i32;
99 let height = y1_sub - y0_sub;
100
101 let double_area_multiplier =
102 ((x1_sub - x0_sub).abs() + 2 * (border - x0_sub.max(x1_sub))) as u8;
103 let cover = height as i8;
104
105 PixelSegment::new(
106 lines.orders[li as usize],
107 tile_x,
108 tile_y,
109 local_x,
110 local_y,
111 double_area_multiplier,
112 cover,
113 )
114 })
115 .collect_into_vec(&mut self.segments);
116 }
117
118 const BIT_FIELD_LENGTH: [usize; 7] = bit_field_lens::<TW, TH>();
119
120 #[inline]
121 pub fn sort(&mut self) {
122 let offset = Self::BIT_FIELD_LENGTH[3]
124 + Self::BIT_FIELD_LENGTH[4]
125 + Self::BIT_FIELD_LENGTH[5]
126 + Self::BIT_FIELD_LENGTH[6];
127 self.segments.par_sort_unstable_by_key(|segment| {
128 let segment: u64 = segment.into();
129 segment >> offset
130 });
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 use crate::{GeomId, Layer, LinesBuilder, Order, Point, TILE_HEIGHT, TILE_WIDTH};
139
140 fn segments(p0: Point, p1: Point) -> Vec<PixelSegment<TILE_WIDTH, TILE_HEIGHT>> {
141 let mut builder = LinesBuilder::new();
142 builder.push(GeomId::default(), [p0, p1]);
143 let lines = builder
144 .build(|_| Some(Layer { order: Some(Order::new(0).unwrap()), ..Default::default() }));
145
146 let mut rasterizer = Rasterizer::default();
147 rasterizer.rasterize(&lines);
148
149 rasterizer.segments().to_vec()
150 }
151
152 fn areas_and_covers(segments: &[PixelSegment<TILE_WIDTH, TILE_HEIGHT>]) -> Vec<(i16, i8)> {
153 segments
154 .iter()
155 .map(|&segment| {
156 let segment: PixelSegmentUnpacked = segment.into();
157 (segment.double_area, segment.cover)
158 })
159 .collect()
160 }
161
162 #[test]
163 fn area_cover_octant_1() {
164 assert_eq!(
165 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(3.0, 2.0))),
166 [(11 * 16, 11), (5 * 8 + 2 * (5 * 8), 5), (5 * 8, 5), (11 * 16, 11)],
167 );
168 }
169
170 #[test]
171 fn area_cover_octant_2() {
172 assert_eq!(
173 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(2.0, 3.0))),
174 [(16 * 11 + 2 * (16 * 5), 16), (8 * 5, 8), (8 * 5 + 2 * (8 * 11), 8), (16 * 11, 16)],
175 );
176 }
177
178 #[test]
179 fn area_cover_octant_3() {
180 assert_eq!(
181 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-2.0, 3.0))),
182 [(16 * 11, 16), (8 * 5 + 2 * (8 * 11), 8), (8 * 5, 8), (16 * 11 + 2 * (16 * 5), 16)],
183 );
184 }
185
186 #[test]
187 fn area_cover_octant_4() {
188 assert_eq!(
189 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-3.0, 2.0))),
190 [(11 * 16, 11), (5 * 8, 5), (5 * 8 + 2 * (5 * 8), 5), (11 * 16, 11)],
191 );
192 }
193
194 #[test]
195 fn area_cover_octant_5() {
196 assert_eq!(
197 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-3.0, -2.0))),
198 [(-(11 * 16), -11), (-(5 * 8), -5), (-(5 * 8 + 2 * (5 * 8)), -5), (-(11 * 16), -11)],
199 );
200 }
201
202 #[test]
203 fn area_cover_octant_6() {
204 assert_eq!(
205 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-2.0, -3.0))),
206 [
207 (-(16 * 11), -16),
208 (-(8 * 5 + 2 * (8 * 11)), -8),
209 (-(8 * 5), -8),
210 (-(16 * 11 + 2 * (16 * 5)), -16),
211 ],
212 );
213 }
214
215 #[test]
216 fn area_cover_octant_7() {
217 assert_eq!(
218 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(2.0, -3.0))),
219 [
220 (-(16 * 11 + 2 * (16 * 5)), -16),
221 (-(8 * 5), -8),
222 (-(8 * 5 + 2 * (8 * 11)), -8),
223 (-(16 * 11), -16),
224 ],
225 );
226 }
227
228 #[test]
229 fn area_cover_octant_8() {
230 assert_eq!(
231 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(3.0, -2.0))),
232 [(-(11 * 16), -11), (-(5 * 8 + 2 * (5 * 8)), -5), (-(5 * 8), -5), (-(11 * 16), -11)],
233 );
234 }
235
236 #[test]
237 fn area_cover_axis_0() {
238 assert_eq!(areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(1.0, 0.0))), []);
239 }
240
241 #[test]
242 fn area_cover_axis_45() {
243 assert_eq!(
244 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(1.0, 1.0))),
245 [(16 * 16, 16)],
246 );
247 }
248
249 #[test]
250 fn area_cover_axis_90() {
251 assert_eq!(
252 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(0.0, 1.0))),
253 [(2 * 16 * 16, 16)],
254 );
255 }
256
257 #[test]
258 fn area_cover_axis_135() {
259 assert_eq!(
260 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-1.0, 1.0))),
261 [(16 * 16, 16)],
262 );
263 }
264
265 #[test]
266 fn area_cover_axis_180() {
267 assert_eq!(areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-1.0, 0.0))), []);
268 }
269
270 #[test]
271 fn area_cover_axis_225() {
272 assert_eq!(
273 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-1.0, -1.0))),
274 [(-(16 * 16), -16)],
275 );
276 }
277
278 #[test]
279 fn area_cover_axis_270() {
280 assert_eq!(
281 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(0.0, -1.0))),
282 [(2 * -(16 * 16), -16)],
283 );
284 }
285
286 #[test]
287 fn area_cover_axis_315() {
288 assert_eq!(
289 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(-1.0, -1.0))),
290 [(-(16 * 16), -16)],
291 );
292 }
293
294 fn tiles(segments: &[PixelSegment<TILE_WIDTH, TILE_HEIGHT>]) -> Vec<(i16, i16, u8, u8)> {
295 segments
296 .iter()
297 .map(|&segment| {
298 let segment: PixelSegmentUnpacked = segment.into();
299 (segment.tile_x, segment.tile_y, segment.local_x, segment.local_y)
300 })
301 .collect()
302 }
303
304 #[test]
305 fn tile_octant_1() {
306 assert_eq!(
307 tiles(&segments(
308 Point::new(TILE_WIDTH as f32, TILE_HEIGHT as f32),
309 Point::new(TILE_WIDTH as f32 + 3.0, TILE_HEIGHT as f32 + 2.0),
310 )),
311 [(1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1), (1, 1, 2, 1)],
312 );
313 }
314
315 #[test]
316 fn tile_octant_2() {
317 assert_eq!(
318 tiles(&segments(
319 Point::new(TILE_WIDTH as f32, TILE_HEIGHT as f32),
320 Point::new(TILE_WIDTH as f32 + 2.0, TILE_HEIGHT as f32 + 3.0),
321 )),
322 [(1, 1, 0, 0), (1, 1, 0, 1), (1, 1, 1, 1), (1, 1, 1, 2)],
323 );
324 }
325
326 #[test]
327 fn tile_octant_3() {
328 assert_eq!(
329 tiles(&segments(
330 Point::new(-(TILE_WIDTH as f32), TILE_HEIGHT as f32),
331 Point::new(-(TILE_WIDTH as f32) - 2.0, TILE_HEIGHT as f32 + 3.0),
332 )),
333 [
334 (-1, 1, TILE_WIDTH as u8 - 1, 0),
335 (-1, 1, TILE_WIDTH as u8 - 1, 1),
336 (-1, 1, TILE_WIDTH as u8 - 2, 1),
337 (-1, 1, TILE_WIDTH as u8 - 2, 2),
338 ],
339 );
340 }
341
342 #[test]
343 fn tile_octant_4() {
344 assert_eq!(
345 tiles(&segments(
346 Point::new(-(TILE_WIDTH as f32), TILE_HEIGHT as f32),
347 Point::new(-(TILE_WIDTH as f32) - 3.0, TILE_HEIGHT as f32 + 2.0),
348 )),
349 [
350 (-1, 1, TILE_WIDTH as u8 - 1, 0),
351 (-1, 1, TILE_WIDTH as u8 - 2, 0),
352 (-1, 1, TILE_WIDTH as u8 - 2, 1),
353 (-1, 1, TILE_WIDTH as u8 - 3, 1),
354 ],
355 );
356 }
357
358 #[test]
359 fn tile_octant_5() {
360 assert_eq!(
361 tiles(&segments(
362 Point::new(-(TILE_WIDTH as f32), -(TILE_HEIGHT as f32)),
363 Point::new(-(TILE_WIDTH as f32) - 3.0, -(TILE_HEIGHT as f32) - 2.0),
364 )),
365 [
366 (-1, -1, TILE_WIDTH as u8 - 1, TILE_HEIGHT as u8 - 1),
367 (-1, -1, TILE_WIDTH as u8 - 2, TILE_HEIGHT as u8 - 1),
368 (-1, -1, TILE_WIDTH as u8 - 2, TILE_HEIGHT as u8 - 2),
369 (-1, -1, TILE_WIDTH as u8 - 3, TILE_HEIGHT as u8 - 2),
370 ],
371 );
372 }
373
374 #[test]
375 fn tile_octant_6() {
376 assert_eq!(
377 tiles(&segments(
378 Point::new(-(TILE_WIDTH as f32), -(TILE_HEIGHT as f32)),
379 Point::new(-(TILE_WIDTH as f32) - 2.0, -(TILE_HEIGHT as f32) - 3.0),
380 )),
381 [
382 (-1, -1, TILE_WIDTH as u8 - 1, TILE_HEIGHT as u8 - 1),
383 (-1, -1, TILE_WIDTH as u8 - 1, TILE_HEIGHT as u8 - 2),
384 (-1, -1, TILE_WIDTH as u8 - 2, TILE_HEIGHT as u8 - 2),
385 (-1, -1, TILE_WIDTH as u8 - 2, TILE_HEIGHT as u8 - 3),
386 ],
387 );
388 }
389
390 #[test]
391 fn tile_octant_7() {
392 assert_eq!(
393 tiles(&segments(
394 Point::new(TILE_WIDTH as f32, -(TILE_HEIGHT as f32)),
395 Point::new(TILE_WIDTH as f32 + 2.0, -(TILE_HEIGHT as f32) - 3.0),
396 )),
397 [
398 (1, -1, 0, TILE_HEIGHT as u8 - 1),
399 (1, -1, 0, TILE_HEIGHT as u8 - 2),
400 (1, -1, 1, TILE_HEIGHT as u8 - 2),
401 (1, -1, 1, TILE_HEIGHT as u8 - 3),
402 ],
403 );
404 }
405
406 #[test]
407 fn tile_octant_8() {
408 assert_eq!(
409 tiles(&segments(
410 Point::new(TILE_WIDTH as f32, -(TILE_HEIGHT as f32)),
411 Point::new(TILE_WIDTH as f32 + 3.0, -(TILE_HEIGHT as f32) - 2.0),
412 )),
413 [
414 (1, -1, 0, TILE_HEIGHT as u8 - 1),
415 (1, -1, 1, TILE_HEIGHT as u8 - 1),
416 (1, -1, 1, TILE_HEIGHT as u8 - 2),
417 (1, -1, 2, TILE_HEIGHT as u8 - 2),
418 ],
419 );
420 }
421
422 #[test]
423 fn start_and_end_not_on_pixel_border() {
424 assert_eq!(
425 areas_and_covers(&segments(Point::new(0.5, 0.25), Point::new(4.0, 2.0)))[0],
426 (4 * 8, 4),
427 );
428
429 assert_eq!(
430 areas_and_covers(&segments(Point::new(0.0, 0.0), Point::new(3.5, 1.75)))[4],
431 (4 * 8 + 2 * (4 * 8), 4),
432 );
433 }
434}