1use crate::basics::{iround, RectI};
10use crate::dda_line::Dda2LineInterpolator;
11use crate::ellipse_bresenham::EllipseBresenhamInterpolator;
12use crate::line_aa_basics::*;
13use crate::math::fast_sqrt;
14use crate::pixfmt_rgba::PixelFormat;
15use crate::renderer_base::RendererBase;
16
17const PROFILE_SUBPIXEL_SHIFT: i32 = LINE_SUBPIXEL_SHIFT; const PROFILE_SUBPIXEL_SCALE: i32 = 1 << PROFILE_SUBPIXEL_SHIFT; const PROFILE_AA_SHIFT: i32 = 8;
25const PROFILE_AA_SCALE: i32 = 1 << PROFILE_AA_SHIFT; const PROFILE_AA_MASK: i32 = PROFILE_AA_SCALE - 1; pub struct LineProfileAa {
34 profile: Vec<u8>,
35 gamma: [u8; 256],
36 subpixel_width: i32,
37 min_width: f64,
38 smoother_width: f64,
39}
40
41impl LineProfileAa {
42 pub fn new() -> Self {
43 let mut s = Self {
44 profile: Vec::new(),
45 gamma: [0u8; 256],
46 subpixel_width: 0,
47 min_width: 1.0,
48 smoother_width: 1.0,
49 };
50 for i in 0..256 {
52 s.gamma[i] = i as u8;
53 }
54 s
55 }
56
57 pub fn with_width(w: f64) -> Self {
59 let mut s = Self::new();
60 s.set_width(w);
61 s
62 }
63
64 pub fn min_width(&self) -> f64 {
65 self.min_width
66 }
67 pub fn smoother_width(&self) -> f64 {
68 self.smoother_width
69 }
70 pub fn subpixel_width(&self) -> i32 {
71 self.subpixel_width
72 }
73
74 pub fn set_min_width(&mut self, w: f64) {
75 self.min_width = w;
76 }
77 pub fn set_smoother_width(&mut self, w: f64) {
78 self.smoother_width = w;
79 }
80
81 pub fn set_width(&mut self, mut w: f64) {
84 if w < 0.0 { w = 0.0; }
85
86 if w < self.smoother_width {
87 w += w;
88 } else {
89 w += self.smoother_width;
90 }
91
92 w *= 0.5;
93 w -= self.smoother_width;
94 let mut s = self.smoother_width;
95 if w < 0.0 {
96 s += w;
97 w = 0.0;
98 }
99 self.build_profile(w, s);
100 }
101
102 pub fn set_gamma<F: Fn(f64) -> f64>(&mut self, gamma_fn: F) {
104 for i in 0..256 {
105 self.gamma[i] = iround(gamma_fn(i as f64 / 255.0) * 255.0) as u8;
106 }
107 }
108
109 #[inline]
111 pub fn value(&self, dist: i32) -> u8 {
112 let idx = (dist + PROFILE_SUBPIXEL_SCALE * 2) as usize;
113 if idx < self.profile.len() {
114 self.profile[idx]
115 } else {
116 0
117 }
118 }
119
120 fn profile_size(&self) -> usize {
121 self.profile.len()
122 }
123
124 fn build_profile(&mut self, center_width: f64, smoother_width: f64) {
126 let mut base_val = 1.0f64;
127 let mut cw = center_width;
128 let mut sw = smoother_width;
129
130 if cw == 0.0 {
131 cw = 1.0 / PROFILE_SUBPIXEL_SCALE as f64;
132 }
133 if sw == 0.0 {
134 sw = 1.0 / PROFILE_SUBPIXEL_SCALE as f64;
135 }
136
137 let width = cw + sw;
138 if width < self.min_width {
139 let k = width / self.min_width;
140 base_val *= k;
141 cw /= k;
142 sw /= k;
143 }
144
145 self.subpixel_width = iround((cw + sw) * PROFILE_SUBPIXEL_SCALE as f64);
147 let size = self.subpixel_width as usize + PROFILE_SUBPIXEL_SCALE as usize * 6;
148 self.profile.resize(size, 0);
149
150 let subpixel_center_width = (cw * PROFILE_SUBPIXEL_SCALE as f64) as usize;
151 let subpixel_smoother_width = (sw * PROFILE_SUBPIXEL_SCALE as f64) as usize;
152
153 let ch_center = PROFILE_SUBPIXEL_SCALE as usize * 2;
154
155 let val = self.gamma[(base_val * PROFILE_AA_MASK as f64) as usize];
157 for i in 0..subpixel_center_width {
158 self.profile[ch_center + i] = val;
159 }
160
161 let ch_smoother = ch_center + subpixel_center_width;
163 for i in 0..subpixel_smoother_width {
164 let k = base_val - base_val * (i as f64 / subpixel_smoother_width as f64);
165 self.profile[ch_smoother + i] =
166 self.gamma[(k * PROFILE_AA_MASK as f64) as usize];
167 }
168
169 let n_smoother = size
171 - subpixel_smoother_width
172 - subpixel_center_width
173 - PROFILE_SUBPIXEL_SCALE as usize * 2;
174 let gamma_zero = self.gamma[0];
175 for i in 0..n_smoother {
176 self.profile[ch_smoother + subpixel_smoother_width + i] = gamma_zero;
177 }
178
179 let mut src = ch_center;
181 let mut dst = ch_center;
182 for _ in 0..(PROFILE_SUBPIXEL_SCALE as usize * 2) {
183 if dst == 0 || src >= self.profile.len() {
184 break;
185 }
186 dst -= 1;
187 let v = self.profile[src];
188 self.profile[dst] = v;
189 src += 1;
190 }
191 }
192}
193
194impl Default for LineProfileAa {
195 fn default() -> Self {
196 Self::new()
197 }
198}
199
200pub struct DistanceInterpolator0 {
209 dx: i32,
210 dy: i32,
211 dist: i32,
212}
213
214impl DistanceInterpolator0 {
215 pub fn new(x1: i32, y1: i32, x2: i32, y2: i32, x: i32, y: i32) -> Self {
216 let mut dx = line_mr(x2) - line_mr(x1);
217 let mut dy = line_mr(y2) - line_mr(y1);
218 let dist = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(x2)) * dy
219 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(y2)) * dx;
220 dx <<= LINE_MR_SUBPIXEL_SHIFT;
221 dy <<= LINE_MR_SUBPIXEL_SHIFT;
222 Self { dx, dy, dist }
223 }
224
225 #[inline]
226 pub fn inc_x(&mut self) {
227 self.dist += self.dy;
228 }
229
230 #[inline]
231 pub fn dist(&self) -> i32 {
232 self.dist
233 }
234}
235
236pub struct DistanceInterpolator00 {
241 dx1: i32,
242 dy1: i32,
243 dx2: i32,
244 dy2: i32,
245 dist1: i32,
246 dist2: i32,
247}
248
249impl DistanceInterpolator00 {
250 pub fn new(
251 xc: i32, yc: i32,
252 x1: i32, y1: i32,
253 x2: i32, y2: i32,
254 x: i32, y: i32,
255 ) -> Self {
256 let mut dx1 = line_mr(x1) - line_mr(xc);
257 let mut dy1 = line_mr(y1) - line_mr(yc);
258 let mut dx2 = line_mr(x2) - line_mr(xc);
259 let mut dy2 = line_mr(y2) - line_mr(yc);
260 let dist1 = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(x1)) * dy1
261 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(y1)) * dx1;
262 let dist2 = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(x2)) * dy2
263 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(y2)) * dx2;
264 dx1 <<= LINE_MR_SUBPIXEL_SHIFT;
265 dy1 <<= LINE_MR_SUBPIXEL_SHIFT;
266 dx2 <<= LINE_MR_SUBPIXEL_SHIFT;
267 dy2 <<= LINE_MR_SUBPIXEL_SHIFT;
268 Self { dx1, dy1, dx2, dy2, dist1, dist2 }
269 }
270
271 #[inline]
272 pub fn inc_x(&mut self) {
273 self.dist1 += self.dy1;
274 self.dist2 += self.dy2;
275 }
276
277 #[inline]
278 pub fn dist1(&self) -> i32 {
279 self.dist1
280 }
281 #[inline]
282 pub fn dist2(&self) -> i32 {
283 self.dist2
284 }
285}
286
287pub struct DistanceInterpolator1 {
291 dx: i32,
292 dy: i32,
293 dist: i32,
294}
295
296impl DistanceInterpolator1 {
297 pub fn new(x1: i32, y1: i32, x2: i32, y2: i32, x: i32, y: i32) -> Self {
298 let mut dx = x2 - x1;
299 let mut dy = y2 - y1;
300 let dist = iround(
301 (x + LINE_SUBPIXEL_SCALE / 2 - x2) as f64 * dy as f64
302 - (y + LINE_SUBPIXEL_SCALE / 2 - y2) as f64 * dx as f64,
303 );
304 dx <<= LINE_SUBPIXEL_SHIFT;
305 dy <<= LINE_SUBPIXEL_SHIFT;
306 Self { dx, dy, dist }
307 }
308
309 #[inline]
310 pub fn inc_x(&mut self, dy: i32) {
311 self.dist += self.dy;
312 if dy > 0 {
313 self.dist -= self.dx;
314 }
315 if dy < 0 {
316 self.dist += self.dx;
317 }
318 }
319
320 #[inline]
321 pub fn dec_x(&mut self, dy: i32) {
322 self.dist -= self.dy;
323 if dy > 0 {
324 self.dist -= self.dx;
325 }
326 if dy < 0 {
327 self.dist += self.dx;
328 }
329 }
330
331 #[inline]
332 pub fn inc_y(&mut self, dx: i32) {
333 self.dist -= self.dx;
334 if dx > 0 {
335 self.dist += self.dy;
336 }
337 if dx < 0 {
338 self.dist -= self.dy;
339 }
340 }
341
342 #[inline]
343 pub fn dec_y(&mut self, dx: i32) {
344 self.dist += self.dx;
345 if dx > 0 {
346 self.dist += self.dy;
347 }
348 if dx < 0 {
349 self.dist -= self.dy;
350 }
351 }
352
353 #[inline]
354 pub fn dist(&self) -> i32 {
355 self.dist
356 }
357 #[inline]
358 pub fn dx(&self) -> i32 {
359 self.dx
360 }
361 #[inline]
362 pub fn dy(&self) -> i32 {
363 self.dy
364 }
365}
366
367pub struct DistanceInterpolator2 {
371 dx: i32,
372 dy: i32,
373 dx_start: i32,
374 dy_start: i32,
375 dist: i32,
376 dist_start: i32,
377}
378
379impl DistanceInterpolator2 {
380 pub fn new_start(
382 x1: i32, y1: i32, x2: i32, y2: i32, sx: i32, sy: i32, x: i32, y: i32,
383 ) -> Self {
384 let mut dx = x2 - x1;
385 let mut dy = y2 - y1;
386 let mut dx_start = line_mr(sx) - line_mr(x1);
387 let mut dy_start = line_mr(sy) - line_mr(y1);
388 let dist = iround(
389 (x + LINE_SUBPIXEL_SCALE / 2 - x2) as f64 * dy as f64
390 - (y + LINE_SUBPIXEL_SCALE / 2 - y2) as f64 * dx as f64,
391 );
392 let dist_start = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(sx)) * dy_start
393 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(sy)) * dx_start;
394 dx <<= LINE_SUBPIXEL_SHIFT;
395 dy <<= LINE_SUBPIXEL_SHIFT;
396 dx_start <<= LINE_MR_SUBPIXEL_SHIFT;
397 dy_start <<= LINE_MR_SUBPIXEL_SHIFT;
398 Self { dx, dy, dx_start, dy_start, dist, dist_start }
399 }
400
401 pub fn new_end(
403 x1: i32, y1: i32, x2: i32, y2: i32, ex: i32, ey: i32, x: i32, y: i32,
404 ) -> Self {
405 let mut dx = x2 - x1;
406 let mut dy = y2 - y1;
407 let mut dx_start = line_mr(ex) - line_mr(x2);
408 let mut dy_start = line_mr(ey) - line_mr(y2);
409 let dist = iround(
410 (x + LINE_SUBPIXEL_SCALE / 2 - x2) as f64 * dy as f64
411 - (y + LINE_SUBPIXEL_SCALE / 2 - y2) as f64 * dx as f64,
412 );
413 let dist_start = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(ex)) * dy_start
414 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(ey)) * dx_start;
415 dx <<= LINE_SUBPIXEL_SHIFT;
416 dy <<= LINE_SUBPIXEL_SHIFT;
417 dx_start <<= LINE_MR_SUBPIXEL_SHIFT;
418 dy_start <<= LINE_MR_SUBPIXEL_SHIFT;
419 Self { dx, dy, dx_start, dy_start, dist, dist_start }
420 }
421
422 #[inline]
423 pub fn inc_x(&mut self, dy: i32) {
424 self.dist += self.dy;
425 self.dist_start += self.dy_start;
426 if dy > 0 {
427 self.dist -= self.dx;
428 self.dist_start -= self.dx_start;
429 }
430 if dy < 0 {
431 self.dist += self.dx;
432 self.dist_start += self.dx_start;
433 }
434 }
435
436 #[inline]
437 pub fn dec_x(&mut self, dy: i32) {
438 self.dist -= self.dy;
439 self.dist_start -= self.dy_start;
440 if dy > 0 {
441 self.dist -= self.dx;
442 self.dist_start -= self.dx_start;
443 }
444 if dy < 0 {
445 self.dist += self.dx;
446 self.dist_start += self.dx_start;
447 }
448 }
449
450 #[inline]
451 pub fn inc_y(&mut self, dx: i32) {
452 self.dist -= self.dx;
453 self.dist_start -= self.dx_start;
454 if dx > 0 {
455 self.dist += self.dy;
456 self.dist_start += self.dy_start;
457 }
458 if dx < 0 {
459 self.dist -= self.dy;
460 self.dist_start -= self.dy_start;
461 }
462 }
463
464 #[inline]
465 pub fn dec_y(&mut self, dx: i32) {
466 self.dist += self.dx;
467 self.dist_start += self.dx_start;
468 if dx > 0 {
469 self.dist += self.dy;
470 self.dist_start += self.dy_start;
471 }
472 if dx < 0 {
473 self.dist -= self.dy;
474 self.dist_start -= self.dy_start;
475 }
476 }
477
478 #[inline]
479 pub fn dist(&self) -> i32 {
480 self.dist
481 }
482 #[inline]
483 pub fn dist_start(&self) -> i32 {
484 self.dist_start
485 }
486 #[inline]
487 pub fn dist_end(&self) -> i32 {
488 self.dist_start
489 }
490 #[inline]
491 pub fn dx_start(&self) -> i32 {
492 self.dx_start
493 }
494 #[inline]
495 pub fn dy_start(&self) -> i32 {
496 self.dy_start
497 }
498 #[inline]
499 pub fn dx_end(&self) -> i32 {
500 self.dx_start
501 }
502 #[inline]
503 pub fn dy_end(&self) -> i32 {
504 self.dy_start
505 }
506}
507
508pub struct DistanceInterpolator3 {
512 dx: i32,
513 dy: i32,
514 dx_start: i32,
515 dy_start: i32,
516 dx_end: i32,
517 dy_end: i32,
518 dist: i32,
519 dist_start: i32,
520 dist_end: i32,
521}
522
523impl DistanceInterpolator3 {
524 pub fn new(
525 x1: i32, y1: i32, x2: i32, y2: i32,
526 sx: i32, sy: i32, ex: i32, ey: i32,
527 x: i32, y: i32,
528 ) -> Self {
529 let mut dx = x2 - x1;
530 let mut dy = y2 - y1;
531 let mut dx_start = line_mr(sx) - line_mr(x1);
532 let mut dy_start = line_mr(sy) - line_mr(y1);
533 let mut dx_end = line_mr(ex) - line_mr(x2);
534 let mut dy_end = line_mr(ey) - line_mr(y2);
535
536 let dist = iround(
537 (x + LINE_SUBPIXEL_SCALE / 2 - x2) as f64 * dy as f64
538 - (y + LINE_SUBPIXEL_SCALE / 2 - y2) as f64 * dx as f64,
539 );
540 let dist_start = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(sx)) * dy_start
541 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(sy)) * dx_start;
542 let dist_end = (line_mr(x + LINE_SUBPIXEL_SCALE / 2) - line_mr(ex)) * dy_end
543 - (line_mr(y + LINE_SUBPIXEL_SCALE / 2) - line_mr(ey)) * dx_end;
544
545 dx <<= LINE_SUBPIXEL_SHIFT;
546 dy <<= LINE_SUBPIXEL_SHIFT;
547 dx_start <<= LINE_MR_SUBPIXEL_SHIFT;
548 dy_start <<= LINE_MR_SUBPIXEL_SHIFT;
549 dx_end <<= LINE_MR_SUBPIXEL_SHIFT;
550 dy_end <<= LINE_MR_SUBPIXEL_SHIFT;
551
552 Self {
553 dx, dy, dx_start, dy_start, dx_end, dy_end, dist, dist_start, dist_end,
554 }
555 }
556
557 #[inline]
558 pub fn inc_x(&mut self, dy: i32) {
559 self.dist += self.dy;
560 self.dist_start += self.dy_start;
561 self.dist_end += self.dy_end;
562 if dy > 0 {
563 self.dist -= self.dx;
564 self.dist_start -= self.dx_start;
565 self.dist_end -= self.dx_end;
566 }
567 if dy < 0 {
568 self.dist += self.dx;
569 self.dist_start += self.dx_start;
570 self.dist_end += self.dx_end;
571 }
572 }
573
574 #[inline]
575 pub fn dec_x(&mut self, dy: i32) {
576 self.dist -= self.dy;
577 self.dist_start -= self.dy_start;
578 self.dist_end -= self.dy_end;
579 if dy > 0 {
580 self.dist -= self.dx;
581 self.dist_start -= self.dx_start;
582 self.dist_end -= self.dx_end;
583 }
584 if dy < 0 {
585 self.dist += self.dx;
586 self.dist_start += self.dx_start;
587 self.dist_end += self.dx_end;
588 }
589 }
590
591 #[inline]
592 pub fn inc_y(&mut self, dx: i32) {
593 self.dist -= self.dx;
594 self.dist_start -= self.dx_start;
595 self.dist_end -= self.dx_end;
596 if dx > 0 {
597 self.dist += self.dy;
598 self.dist_start += self.dy_start;
599 self.dist_end += self.dy_end;
600 }
601 if dx < 0 {
602 self.dist -= self.dy;
603 self.dist_start -= self.dy_start;
604 self.dist_end -= self.dy_end;
605 }
606 }
607
608 #[inline]
609 pub fn dec_y(&mut self, dx: i32) {
610 self.dist += self.dx;
611 self.dist_start += self.dx_start;
612 self.dist_end += self.dx_end;
613 if dx > 0 {
614 self.dist += self.dy;
615 self.dist_start += self.dy_start;
616 self.dist_end += self.dy_end;
617 }
618 if dx < 0 {
619 self.dist -= self.dy;
620 self.dist_start -= self.dy_start;
621 self.dist_end -= self.dy_end;
622 }
623 }
624
625 #[inline]
626 pub fn dist(&self) -> i32 {
627 self.dist
628 }
629 #[inline]
630 pub fn dist_start(&self) -> i32 {
631 self.dist_start
632 }
633 #[inline]
634 pub fn dist_end(&self) -> i32 {
635 self.dist_end
636 }
637 #[inline]
638 pub fn dx_start(&self) -> i32 {
639 self.dx_start
640 }
641 #[inline]
642 pub fn dy_start(&self) -> i32 {
643 self.dy_start
644 }
645 #[inline]
646 pub fn dx_end(&self) -> i32 {
647 self.dx_end
648 }
649 #[inline]
650 pub fn dy_end(&self) -> i32 {
651 self.dy_end
652 }
653}
654
655pub const MAX_HALF_WIDTH: usize = 64;
660
661pub trait OutlineAaRenderer {
669 fn accurate_join_only(&self) -> bool;
672
673 fn line0(&mut self, lp: &LineParameters);
675
676 fn line1(&mut self, lp: &LineParameters, sx: i32, sy: i32);
678
679 fn line2(&mut self, lp: &LineParameters, ex: i32, ey: i32);
681
682 fn line3(&mut self, lp: &LineParameters, sx: i32, sy: i32, ex: i32, ey: i32);
684
685 fn semidot(&mut self, cmp: fn(i32) -> bool, xc1: i32, yc1: i32, xc2: i32, yc2: i32);
687
688 fn pie(&mut self, xc: i32, yc: i32, x1: i32, y1: i32, x2: i32, y2: i32);
690}
691
692pub struct RendererOutlineAa<'a, PF: PixelFormat> {
702 ren: &'a mut RendererBase<PF>,
703 profile: &'a LineProfileAa,
704 color: PF::ColorType,
705 clip_box: RectI,
706 clipping: bool,
707}
708
709impl<'a, PF: PixelFormat> RendererOutlineAa<'a, PF>
710where
711 PF::ColorType: Default + Clone,
712{
713 pub fn new(ren: &'a mut RendererBase<PF>, profile: &'a LineProfileAa) -> Self {
714 Self {
715 ren,
716 profile,
717 color: PF::ColorType::default(),
718 clip_box: RectI::new(0, 0, 0, 0),
719 clipping: false,
720 }
721 }
722
723 pub fn ren(&self) -> &RendererBase<PF> {
724 self.ren
725 }
726
727 pub fn set_color(&mut self, c: PF::ColorType) {
728 self.color = c;
729 }
730
731 pub fn color(&self) -> &PF::ColorType {
732 &self.color
733 }
734
735 pub fn subpixel_width(&self) -> i32 {
736 self.profile.subpixel_width()
737 }
738
739 pub fn set_clip_box(&mut self, x1: f64, y1: f64, x2: f64, y2: f64) {
740 self.clip_box = RectI::new(
741 line_coord_sat(x1),
742 line_coord_sat(y1),
743 line_coord_sat(x2),
744 line_coord_sat(y2),
745 );
746 self.clipping = true;
747 }
748
749 pub fn reset_clipping(&mut self) {
750 self.clipping = false;
751 }
752
753 #[inline]
754 fn cover(&self, d: i32) -> u8 {
755 self.profile.value(d)
756 }
757
758 pub fn line0(&mut self, lp: &LineParameters) {
760 if self.clipping {
761 let (mut x1, mut y1, mut x2, mut y2) = (lp.x1, lp.y1, lp.x2, lp.y2);
762 let flags = clip_line_segment(&mut x1, &mut y1, &mut x2, &mut y2, &self.clip_box);
763 if flags >= 4 {
764 return;
765 }
766 if flags != 0 {
767 let lp2 = LineParameters::new(
768 x1, y1, x2, y2,
769 uround(calc_distance_i(x1, y1, x2, y2)),
770 );
771 self.line0_no_clip(&lp2);
772 return;
773 }
774 }
775 self.line0_no_clip(lp);
776 }
777
778 fn line0_no_clip(&mut self, lp: &LineParameters) {
779 if lp.len > LINE_MAX_LENGTH {
780 let (lp1, lp2) = lp.divide();
781 self.line0_no_clip(&lp1);
782 self.line0_no_clip(&lp2);
783 return;
784 }
785
786 let li = LineInterpolatorAa0::new(lp, self.profile.subpixel_width());
787 if li.count > 0 {
788 if lp.vertical {
789 self.draw_line0_ver(li, lp);
790 } else {
791 self.draw_line0_hor(li, lp);
792 }
793 }
794 }
795
796 fn draw_line0_hor(&mut self, mut li: LineInterpolatorAa0, lp: &LineParameters) {
797 while let Some(span) = li.step_hor(self.profile, lp) {
798 let x = li.x();
799 let y = li.y() - span.offset as i32 + 1;
800 self.ren.blend_solid_vspan(
801 x, y, span.len as i32, &self.color,
802 &li.covers[span.p0..span.p0 + span.len],
803 );
804 }
805 }
806
807 fn draw_line0_ver(&mut self, mut li: LineInterpolatorAa0, lp: &LineParameters) {
808 while let Some(span) = li.step_ver(self.profile, lp) {
809 let x = li.x() - span.offset as i32 + 1;
810 let y = li.y();
811 self.ren.blend_solid_hspan(
812 x, y, span.len as i32, &self.color,
813 &li.covers[span.p0..span.p0 + span.len],
814 );
815 }
816 }
817
818 pub fn line1(&mut self, lp: &LineParameters, sx: i32, sy: i32) {
820 if self.clipping {
821 let (mut x1, mut y1, mut x2, mut y2) = (lp.x1, lp.y1, lp.x2, lp.y2);
822 let flags = clip_line_segment(&mut x1, &mut y1, &mut x2, &mut y2, &self.clip_box);
823 if flags >= 4 {
824 return;
825 }
826 if flags != 0 {
827 let lp2 = LineParameters::new(
828 x1, y1, x2, y2,
829 uround(calc_distance_i(x1, y1, x2, y2)),
830 );
831 if flags & 1 != 0 {
832 self.line0_no_clip(&lp2);
834 } else {
835 self.line1_no_clip(&lp2, sx, sy);
836 }
837 return;
838 }
839 }
840 self.line1_no_clip(lp, sx, sy);
841 }
842
843 fn line1_no_clip(&mut self, lp: &LineParameters, mut sx: i32, mut sy: i32) {
844 if lp.len > LINE_MAX_LENGTH {
845 let (lp1, lp2) = lp.divide();
846 self.line1_no_clip(
847 &lp1,
848 (lp.x1 + sx) >> 1,
849 (lp.y1 + sy) >> 1,
850 );
851 self.line1_no_clip(
852 &lp2,
853 lp1.x2 + (lp1.y2 - lp1.y1),
854 lp1.y2 - (lp1.x2 - lp1.x1),
855 );
856 return;
857 }
858
859 fix_degenerate_bisectrix_start(lp, &mut sx, &mut sy);
860 let li = LineInterpolatorAa1::new(lp, sx, sy, self.profile.subpixel_width());
861 if lp.vertical {
862 self.draw_line1_ver(li, lp);
863 } else {
864 self.draw_line1_hor(li, lp);
865 }
866 }
867
868 fn draw_line1_hor(&mut self, mut li: LineInterpolatorAa1, lp: &LineParameters) {
869 while let Some(span) = li.step_hor(self.profile, lp) {
870 self.ren.blend_solid_vspan(
871 li.x(), li.y() - span.offset as i32 + 1, span.len as i32, &self.color,
872 &li.covers[span.p0..span.p0 + span.len],
873 );
874 }
875 }
876
877 fn draw_line1_ver(&mut self, mut li: LineInterpolatorAa1, lp: &LineParameters) {
878 while let Some(span) = li.step_ver(self.profile, lp) {
879 self.ren.blend_solid_hspan(
880 li.x() - span.offset as i32 + 1, li.y(), span.len as i32, &self.color,
881 &li.covers[span.p0..span.p0 + span.len],
882 );
883 }
884 }
885
886 pub fn line2(&mut self, lp: &LineParameters, ex: i32, ey: i32) {
888 if self.clipping {
889 let (mut x1, mut y1, mut x2, mut y2) = (lp.x1, lp.y1, lp.x2, lp.y2);
890 let flags = clip_line_segment(&mut x1, &mut y1, &mut x2, &mut y2, &self.clip_box);
891 if flags >= 4 {
892 return;
893 }
894 if flags != 0 {
895 let lp2 = LineParameters::new(
896 x1, y1, x2, y2,
897 uround(calc_distance_i(x1, y1, x2, y2)),
898 );
899 if flags & 2 != 0 {
900 self.line0_no_clip(&lp2);
901 } else {
902 self.line2_no_clip(&lp2, ex, ey);
903 }
904 return;
905 }
906 }
907 self.line2_no_clip(lp, ex, ey);
908 }
909
910 fn line2_no_clip(&mut self, lp: &LineParameters, mut ex: i32, mut ey: i32) {
911 if lp.len > LINE_MAX_LENGTH {
912 let (lp1, lp2) = lp.divide();
913 self.line2_no_clip(
914 &lp1,
915 lp1.x2 + (lp1.y2 - lp1.y1),
916 lp1.y2 - (lp1.x2 - lp1.x1),
917 );
918 self.line2_no_clip(
919 &lp2,
920 (lp.x2 + ex) >> 1,
921 (lp.y2 + ey) >> 1,
922 );
923 return;
924 }
925
926 fix_degenerate_bisectrix_end(lp, &mut ex, &mut ey);
927 let li = LineInterpolatorAa2::new(lp, ex, ey, self.profile.subpixel_width());
928 if lp.vertical {
929 self.draw_line2_ver(li, lp);
930 } else {
931 self.draw_line2_hor(li, lp);
932 }
933 }
934
935 fn draw_line2_hor(&mut self, mut li: LineInterpolatorAa2, lp: &LineParameters) {
936 while let Some(span) = li.step_hor(self.profile, lp) {
937 self.ren.blend_solid_vspan(
938 li.x(), li.y() - span.offset as i32 + 1, span.len as i32, &self.color,
939 &li.covers[span.p0..span.p0 + span.len],
940 );
941 }
942 }
943
944 fn draw_line2_ver(&mut self, mut li: LineInterpolatorAa2, lp: &LineParameters) {
945 while let Some(span) = li.step_ver(self.profile, lp) {
946 self.ren.blend_solid_hspan(
947 li.x() - span.offset as i32 + 1, li.y(), span.len as i32, &self.color,
948 &li.covers[span.p0..span.p0 + span.len],
949 );
950 }
951 }
952
953 pub fn line3(
955 &mut self,
956 lp: &LineParameters,
957 sx: i32,
958 sy: i32,
959 ex: i32,
960 ey: i32,
961 ) {
962 if self.clipping {
963 let (mut x1, mut y1, mut x2, mut y2) = (lp.x1, lp.y1, lp.x2, lp.y2);
964 let flags = clip_line_segment(&mut x1, &mut y1, &mut x2, &mut y2, &self.clip_box);
965 if flags >= 4 {
966 return;
967 }
968 if flags != 0 {
969 let lp2 = LineParameters::new(
970 x1, y1, x2, y2,
971 uround(calc_distance_i(x1, y1, x2, y2)),
972 );
973 match flags & 3 {
974 3 => self.line0_no_clip(&lp2),
975 1 => self.line2_no_clip(&lp2, ex, ey),
976 2 => self.line1_no_clip(&lp2, sx, sy),
977 _ => self.line3_no_clip(&lp2, sx, sy, ex, ey),
978 }
979 return;
980 }
981 }
982 self.line3_no_clip(lp, sx, sy, ex, ey);
983 }
984
985 fn line3_no_clip(
986 &mut self,
987 lp: &LineParameters,
988 mut sx: i32,
989 mut sy: i32,
990 mut ex: i32,
991 mut ey: i32,
992 ) {
993 if lp.len > LINE_MAX_LENGTH {
994 let (lp1, lp2) = lp.divide();
995 let mx = lp1.x2 + (lp1.y2 - lp1.y1);
996 let my = lp1.y2 - (lp1.x2 - lp1.x1);
997 self.line3_no_clip(
998 &lp1,
999 (lp.x1 + sx) >> 1,
1000 (lp.y1 + sy) >> 1,
1001 mx, my,
1002 );
1003 self.line3_no_clip(
1004 &lp2,
1005 mx, my,
1006 (lp.x2 + ex) >> 1,
1007 (lp.y2 + ey) >> 1,
1008 );
1009 return;
1010 }
1011
1012 fix_degenerate_bisectrix_start(lp, &mut sx, &mut sy);
1013 fix_degenerate_bisectrix_end(lp, &mut ex, &mut ey);
1014 let li = LineInterpolatorAa3::new(lp, sx, sy, ex, ey, self.profile.subpixel_width());
1015 if lp.vertical {
1016 self.draw_line3_ver(li, lp);
1017 } else {
1018 self.draw_line3_hor(li, lp);
1019 }
1020 }
1021
1022 fn draw_line3_hor(&mut self, mut li: LineInterpolatorAa3, lp: &LineParameters) {
1023 while let Some(span) = li.step_hor(self.profile, lp) {
1024 self.ren.blend_solid_vspan(
1025 li.x(), li.y() - span.offset as i32 + 1, span.len as i32, &self.color,
1026 &li.covers[span.p0..span.p0 + span.len],
1027 );
1028 }
1029 }
1030
1031 fn draw_line3_ver(&mut self, mut li: LineInterpolatorAa3, lp: &LineParameters) {
1032 while let Some(span) = li.step_ver(self.profile, lp) {
1033 self.ren.blend_solid_hspan(
1034 li.x() - span.offset as i32 + 1, li.y(), span.len as i32, &self.color,
1035 &li.covers[span.p0..span.p0 + span.len],
1036 );
1037 }
1038 }
1039
1040 pub fn semidot<F: Fn(i32) -> bool>(
1043 &mut self,
1044 cmp: F,
1045 xc1: i32,
1046 yc1: i32,
1047 xc2: i32,
1048 yc2: i32,
1049 ) {
1050 let r = ((self.profile.subpixel_width() + LINE_SUBPIXEL_MASK) >> LINE_SUBPIXEL_SHIFT) as i32;
1051 if r < 1 {
1052 return;
1053 }
1054 let mut ei = EllipseBresenhamInterpolator::new(r, r);
1055 let mut dx = 0i32;
1056 let mut dy = -r;
1057 let mut dy0 = dy;
1058 let mut dx0 = dx;
1059
1060 let x = xc1 >> LINE_SUBPIXEL_SHIFT;
1061 let y = yc1 >> LINE_SUBPIXEL_SHIFT;
1062
1063 loop {
1064 dx += ei.dx();
1065 dy += ei.dy();
1066 if dy != dy0 {
1067 self.semidot_hline(&cmp, xc1, yc1, xc2, yc2, x - dx0, y + dy0, x + dx0);
1068 self.semidot_hline(&cmp, xc1, yc1, xc2, yc2, x - dx0, y - dy0, x + dx0);
1069 }
1070 dx0 = dx;
1071 dy0 = dy;
1072 ei.next();
1073 if dy >= 0 {
1074 break;
1075 }
1076 }
1077 self.semidot_hline(&cmp, xc1, yc1, xc2, yc2, x - dx0, y + dy0, x + dx0);
1078 }
1079
1080 fn semidot_hline<F: Fn(i32) -> bool>(
1083 &mut self,
1084 cmp: &F,
1085 xc1: i32,
1086 yc1: i32,
1087 xc2: i32,
1088 yc2: i32,
1089 mut x1: i32,
1090 y1: i32,
1091 x2: i32,
1092 ) {
1093 let mut covers = [0u8; MAX_HALF_WIDTH * 2 + 4];
1094 let mut p0 = 0usize;
1095 let mut p1 = 0usize;
1096
1097 let x = x1 << LINE_SUBPIXEL_SHIFT;
1099 let y = y1 << LINE_SUBPIXEL_SHIFT;
1100 let w = self.profile.subpixel_width();
1101
1102 let mut di = DistanceInterpolator0::new(xc1, yc1, xc2, yc2, x, y);
1103
1104 let mut dx = x + LINE_SUBPIXEL_SCALE / 2 - xc1;
1106 let dy = y + LINE_SUBPIXEL_SCALE / 2 - yc1;
1107
1108 loop {
1109 let d = fast_sqrt((dx * dx + dy * dy) as u32) as i32;
1110 covers[p1] = 0;
1111 if cmp(di.dist()) && d <= w {
1112 covers[p1] = self.cover(d);
1113 }
1114 p1 += 1;
1115 dx += LINE_SUBPIXEL_SCALE;
1116 di.inc_x();
1117 x1 += 1;
1118 if x1 > x2 {
1119 break;
1120 }
1121 }
1122
1123 self.ren.blend_solid_hspan(
1124 x1 - (p1 as i32), y1, (p1 - p0) as i32, &self.color, &covers[p0..p1],
1125 );
1126 }
1127
1128 pub fn pie(
1131 &mut self,
1132 xc: i32,
1133 yc: i32,
1134 x1: i32,
1135 y1: i32,
1136 x2: i32,
1137 y2: i32,
1138 ) {
1139 let r = ((self.profile.subpixel_width() + LINE_SUBPIXEL_MASK) >> LINE_SUBPIXEL_SHIFT) as i32;
1140 if r < 1 {
1141 return;
1142 }
1143 let mut ei = EllipseBresenhamInterpolator::new(r, r);
1144 let mut dx = 0i32;
1145 let mut dy = -r;
1146 let mut dy0 = dy;
1147 let mut dx0 = dx;
1148
1149 let x = xc >> LINE_SUBPIXEL_SHIFT;
1150 let y = yc >> LINE_SUBPIXEL_SHIFT;
1151
1152 loop {
1153 dx += ei.dx();
1154 dy += ei.dy();
1155 if dy != dy0 {
1156 self.pie_hline(xc, yc, x1, y1, x2, y2, x - dx0, y + dy0, x + dx0);
1157 self.pie_hline(xc, yc, x1, y1, x2, y2, x - dx0, y - dy0, x + dx0);
1158 }
1159 dx0 = dx;
1160 dy0 = dy;
1161 ei.next();
1162 if dy >= 0 {
1163 break;
1164 }
1165 }
1166 self.pie_hline(xc, yc, x1, y1, x2, y2, x - dx0, y + dy0, x + dx0);
1167 }
1168
1169 fn pie_hline(
1172 &mut self,
1173 xc: i32,
1174 yc: i32,
1175 xp1: i32,
1176 yp1: i32,
1177 xp2: i32,
1178 yp2: i32,
1179 mut xh1: i32,
1180 yh1: i32,
1181 xh2: i32,
1182 ) {
1183 let mut covers = [0u8; MAX_HALF_WIDTH * 2 + 4];
1184 let mut p0 = 0usize;
1185 let mut p1 = 0usize;
1186
1187 let x = xh1 << LINE_SUBPIXEL_SHIFT;
1188 let y = yh1 << LINE_SUBPIXEL_SHIFT;
1189 let w = self.profile.subpixel_width();
1190
1191 let mut di = DistanceInterpolator00::new(
1192 xc, yc, xp1, yp1, xp2, yp2, x, y,
1193 );
1194
1195 let mut dx = x + LINE_SUBPIXEL_SCALE / 2 - xc;
1196 let dy = y + LINE_SUBPIXEL_SCALE / 2 - yc;
1197
1198 let xh0 = xh1;
1199 loop {
1200 let d = fast_sqrt((dx * dx + dy * dy) as u32) as i32;
1201 covers[p1] = 0;
1202 if di.dist1() <= 0 && di.dist2() > 0 && d <= w {
1203 covers[p1] = self.cover(d);
1204 }
1205 p1 += 1;
1206 dx += LINE_SUBPIXEL_SCALE;
1207 di.inc_x();
1208 xh1 += 1;
1209 if xh1 > xh2 {
1210 break;
1211 }
1212 }
1213
1214 self.ren.blend_solid_hspan(
1215 xh0, yh1, (p1 - p0) as i32, &self.color, &covers[p0..p1],
1216 );
1217 }
1218}
1219
1220impl<'a, PF: PixelFormat> OutlineAaRenderer for RendererOutlineAa<'a, PF>
1222where
1223 PF::ColorType: Default + Clone,
1224{
1225 fn accurate_join_only(&self) -> bool {
1226 false
1227 }
1228
1229 fn line0(&mut self, lp: &LineParameters) {
1230 self.line0(lp);
1231 }
1232
1233 fn line1(&mut self, lp: &LineParameters, sx: i32, sy: i32) {
1234 self.line1(lp, sx, sy);
1235 }
1236
1237 fn line2(&mut self, lp: &LineParameters, ex: i32, ey: i32) {
1238 self.line2(lp, ex, ey);
1239 }
1240
1241 fn line3(&mut self, lp: &LineParameters, sx: i32, sy: i32, ex: i32, ey: i32) {
1242 self.line3(lp, sx, sy, ex, ey);
1243 }
1244
1245 fn semidot(&mut self, cmp: fn(i32) -> bool, xc1: i32, yc1: i32, xc2: i32, yc2: i32) {
1246 self.semidot(cmp, xc1, yc1, xc2, yc2);
1247 }
1248
1249 fn pie(&mut self, xc: i32, yc: i32, x1: i32, y1: i32, x2: i32, y2: i32) {
1250 self.pie(xc, yc, x1, y1, x2, y2);
1251 }
1252}
1253
1254#[inline]
1259fn calc_distance_i(x1: i32, y1: i32, x2: i32, y2: i32) -> f64 {
1260 let dx = (x2 - x1) as f64;
1261 let dy = (y2 - y1) as f64;
1262 (dx * dx + dy * dy).sqrt()
1263}
1264
1265#[inline]
1266fn uround(v: f64) -> i32 {
1267 (v + 0.5) as i32
1268}
1269
1270const COVER_SIZE: usize = MAX_HALF_WIDTH * 2 + 4;
1275const DIST_SIZE: usize = MAX_HALF_WIDTH + 1;
1276
1277struct LineSpan {
1279 p0: usize,
1281 len: usize,
1283 offset: i32,
1286}
1287
1288fn init_line_interpolator_base(lp: &LineParameters, width: i32) -> (
1290 Dda2LineInterpolator, i32, i32, i32, i32, i32, [i32; DIST_SIZE], ) {
1298 let max_extent = (width + LINE_SUBPIXEL_MASK) >> LINE_SUBPIXEL_SHIFT;
1299
1300 let x;
1301 let y;
1302 let count;
1303 let li;
1304
1305 if lp.vertical {
1306 x = lp.x1 >> LINE_SUBPIXEL_SHIFT;
1307 y = lp.y1 >> LINE_SUBPIXEL_SHIFT;
1308 count = ((lp.y2 >> LINE_SUBPIXEL_SHIFT) - y).abs();
1309 li = Dda2LineInterpolator::new_relative(
1310 line_dbl_hr(lp.x2 - lp.x1),
1311 (lp.y2 - lp.y1).abs(),
1312 );
1313 } else {
1314 x = lp.x1 >> LINE_SUBPIXEL_SHIFT;
1315 y = lp.y1 >> LINE_SUBPIXEL_SHIFT;
1316 count = ((lp.x2 >> LINE_SUBPIXEL_SHIFT) - x).abs();
1317 li = Dda2LineInterpolator::new_relative(
1318 line_dbl_hr(lp.y2 - lp.y1),
1319 (lp.x2 - lp.x1).abs() + 1,
1320 );
1321 };
1322
1323 let len = if lp.vertical == (lp.inc > 0) { -lp.len } else { lp.len };
1324
1325 let mut dist = [0i32; DIST_SIZE];
1327 let mut dd = Dda2LineInterpolator::new_forward(
1328 0,
1329 if lp.vertical { lp.dy << LINE_SUBPIXEL_SHIFT } else { lp.dx << LINE_SUBPIXEL_SHIFT },
1330 lp.len,
1331 );
1332 let stop = width + LINE_SUBPIXEL_SCALE * 2;
1333 let mut i = 0;
1334 while i < MAX_HALF_WIDTH {
1335 dist[i] = dd.y();
1336 if dist[i] >= stop {
1337 break;
1338 }
1339 dd.inc();
1340 i += 1;
1341 }
1342 if i < DIST_SIZE {
1343 dist[i] = 0x7FFF_0000;
1344 }
1345
1346 (li, x, y, count, len, max_extent, dist)
1347}
1348
1349struct LineInterpolatorAa0 {
1352 di: DistanceInterpolator1,
1353 li: Dda2LineInterpolator,
1354 x: i32,
1355 y: i32,
1356 old_x: i32,
1357 old_y: i32,
1358 count: i32,
1359 width: i32,
1360 max_extent: i32,
1361 len: i32,
1362 step: i32,
1363 dist: [i32; DIST_SIZE],
1364 pub covers: [u8; COVER_SIZE],
1365}
1366
1367impl LineInterpolatorAa0 {
1368 fn new(lp: &LineParameters, subpixel_width: i32) -> Self {
1369 let (mut li, x, y, count, len, max_extent, dist) =
1370 init_line_interpolator_base(lp, subpixel_width);
1371
1372 let di = DistanceInterpolator1::new(
1375 lp.x1, lp.y1, lp.x2, lp.y2,
1376 lp.x1 & !LINE_SUBPIXEL_MASK,
1377 lp.y1 & !LINE_SUBPIXEL_MASK,
1378 );
1379
1380 li.adjust_forward();
1381
1382 Self {
1383 di,
1384 li,
1385 x,
1386 y,
1387 old_x: x,
1388 old_y: y,
1389 count,
1390 width: subpixel_width,
1391 max_extent,
1392 len,
1393 step: 0,
1394 dist,
1395 covers: [0u8; COVER_SIZE],
1396 }
1397 }
1398
1399 fn x(&self) -> i32 { self.x }
1400 fn y(&self) -> i32 { self.y }
1401
1402 fn step_hor(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
1403 if self.step >= self.count { return None; }
1406
1407 self.li.inc();
1408 self.x += lp.inc;
1409 self.y = (lp.y1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
1410
1411 if lp.inc > 0 {
1412 self.di.inc_x(self.y - self.old_y);
1413 } else {
1414 self.di.dec_x(self.y - self.old_y);
1415 }
1416 self.old_y = self.y;
1417
1418 let s1 = self.di.dist() / self.len;
1419
1420 let center = MAX_HALF_WIDTH + 2;
1421 let mut p0 = center;
1422 let mut p1 = center;
1423
1424 self.covers[p1] = profile.value(s1) as u8;
1425 p1 += 1;
1426
1427 let mut dy = 1usize;
1428 loop {
1429 if dy >= DIST_SIZE { break; }
1430 let dist = self.dist[dy] - s1;
1431 if dist > self.width { break; }
1432 self.covers[p1] = profile.value(dist) as u8;
1433 p1 += 1;
1434 dy += 1;
1435 }
1436
1437 let mut dy = 1usize;
1438 loop {
1439 if dy >= DIST_SIZE { break; }
1440 let dist = self.dist[dy] + s1;
1441 if dist > self.width { break; }
1442 p0 -= 1;
1443 self.covers[p0] = profile.value(dist) as u8;
1444 dy += 1;
1445 }
1446
1447 self.step += 1;
1448
1449 Some(LineSpan {
1450 p0,
1451 len: p1 - p0,
1452 offset: dy as i32,
1453 })
1454 }
1455
1456 fn step_ver(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
1457 if self.step >= self.count { return None; }
1458
1459 self.li.inc();
1460 self.y += lp.inc;
1461 self.x = (lp.x1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
1462
1463 if lp.inc > 0 {
1464 self.di.inc_y(self.x - self.old_x);
1465 } else {
1466 self.di.dec_y(self.x - self.old_x);
1467 }
1468 self.old_x = self.x;
1469
1470 let s1 = self.di.dist() / self.len;
1471
1472 let center = MAX_HALF_WIDTH + 2;
1473 let mut p0 = center;
1474 let mut p1 = center;
1475
1476 self.covers[p1] = profile.value(s1) as u8;
1477 p1 += 1;
1478
1479 let mut dx = 1usize;
1480 loop {
1481 if dx >= DIST_SIZE { break; }
1482 let dist = self.dist[dx] - s1;
1483 if dist > self.width { break; }
1484 self.covers[p1] = profile.value(dist) as u8;
1485 p1 += 1;
1486 dx += 1;
1487 }
1488
1489 let mut dx = 1usize;
1490 loop {
1491 if dx >= DIST_SIZE { break; }
1492 let dist = self.dist[dx] + s1;
1493 if dist > self.width { break; }
1494 p0 -= 1;
1495 self.covers[p0] = profile.value(dist) as u8;
1496 dx += 1;
1497 }
1498
1499 self.step += 1;
1500
1501 Some(LineSpan {
1502 p0,
1503 len: p1 - p0,
1504 offset: dx as i32,
1505 })
1506 }
1507}
1508
1509struct LineInterpolatorAa1 {
1512 di: DistanceInterpolator2,
1513 li: Dda2LineInterpolator,
1514 x: i32,
1515 y: i32,
1516 old_x: i32,
1517 old_y: i32,
1518 count: i32,
1519 width: i32,
1520 max_extent: i32,
1521 len: i32,
1522 step: i32,
1523 dist: [i32; DIST_SIZE],
1524 pub covers: [u8; COVER_SIZE],
1525}
1526
1527impl LineInterpolatorAa1 {
1528 fn new(lp: &LineParameters, sx: i32, sy: i32, subpixel_width: i32) -> Self {
1529 let (mut li, mut x, mut y, count, len, max_extent, dist) =
1530 init_line_interpolator_base(lp, subpixel_width);
1531
1532 let mut di = DistanceInterpolator2::new_start(
1533 lp.x1, lp.y1, lp.x2, lp.y2, sx, sy,
1534 lp.x1 & !LINE_SUBPIXEL_MASK,
1535 lp.y1 & !LINE_SUBPIXEL_MASK,
1536 );
1537
1538 let mut old_x = x;
1539 let mut old_y = y;
1540 let mut step = 0i32;
1541
1542 let mut npix = 1i32;
1544
1545 if lp.vertical {
1546 loop {
1547 li.dec();
1548 y -= lp.inc;
1549 x = (lp.x1 + li.y()) >> LINE_SUBPIXEL_SHIFT;
1550
1551 if lp.inc > 0 {
1552 di.dec_y(x - old_x);
1553 } else {
1554 di.inc_y(x - old_x);
1555 }
1556 old_x = x;
1557
1558 let mut dist1_start = di.dist_start();
1559 let mut dist2_start = dist1_start;
1560
1561 let mut dx = 0;
1562 if dist1_start < 0 { npix += 1; }
1563 loop {
1564 dist1_start += di.dy_start();
1565 dist2_start -= di.dy_start();
1566 if dist1_start < 0 { npix += 1; }
1567 if dist2_start < 0 { npix += 1; }
1568 dx += 1;
1569 if dist[dx as usize] > subpixel_width { break; }
1570 }
1571 step -= 1;
1572 if npix == 0 { break; }
1573 npix = 0;
1574 if step < -max_extent { break; }
1575 }
1576 } else {
1577 loop {
1578 li.dec();
1579 x -= lp.inc;
1580 y = (lp.y1 + li.y()) >> LINE_SUBPIXEL_SHIFT;
1581
1582 if lp.inc > 0 {
1583 di.dec_x(y - old_y);
1584 } else {
1585 di.inc_x(y - old_y);
1586 }
1587 old_y = y;
1588
1589 let mut dist1_start = di.dist_start();
1590 let mut dist2_start = dist1_start;
1591
1592 let mut dy = 0;
1593 if dist1_start < 0 { npix += 1; }
1594 loop {
1595 dist1_start -= di.dx_start();
1596 dist2_start += di.dx_start();
1597 if dist1_start < 0 { npix += 1; }
1598 if dist2_start < 0 { npix += 1; }
1599 dy += 1;
1600 if dist[dy as usize] > subpixel_width { break; }
1601 }
1602 step -= 1;
1603 if npix == 0 { break; }
1604 npix = 0;
1605 if step < -max_extent { break; }
1606 }
1607 }
1608
1609 li.adjust_forward();
1610
1611 Self {
1612 di, li, x, y, old_x, old_y,
1613 count, width: subpixel_width, max_extent, len, step,
1614 dist, covers: [0u8; COVER_SIZE],
1615 }
1616 }
1617
1618 fn x(&self) -> i32 { self.x }
1619 fn y(&self) -> i32 { self.y }
1620
1621 fn step_hor(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
1622 if self.step >= self.count { return None; }
1623
1624 self.li.inc();
1625 self.x += lp.inc;
1626 self.y = (lp.y1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
1627 if lp.inc > 0 { self.di.inc_x(self.y - self.old_y); }
1628 else { self.di.dec_x(self.y - self.old_y); }
1629 self.old_y = self.y;
1630
1631 let s1 = self.di.dist() / self.len;
1632 let mut dist_start = self.di.dist_start();
1633
1634 let center = MAX_HALF_WIDTH + 2;
1635 let mut p0 = center;
1636 let mut p1 = center;
1637
1638 self.covers[p1] = 0;
1639 if dist_start <= 0 {
1640 self.covers[p1] = profile.value(s1) as u8;
1641 }
1642 p1 += 1;
1643
1644 let mut dy = 1usize;
1645 loop {
1646 if dy >= DIST_SIZE { break; }
1647 let dist = self.dist[dy] - s1;
1648 if dist > self.width { break; }
1649 dist_start -= self.di.dx_start();
1650 self.covers[p1] = 0;
1651 if dist_start <= 0 {
1652 self.covers[p1] = profile.value(dist) as u8;
1653 }
1654 p1 += 1;
1655 dy += 1;
1656 }
1657
1658 let mut dy = 1usize;
1659 dist_start = self.di.dist_start();
1660 loop {
1661 if dy >= DIST_SIZE { break; }
1662 let dist = self.dist[dy] + s1;
1663 if dist > self.width { break; }
1664 dist_start += self.di.dx_start();
1665 p0 -= 1;
1666 self.covers[p0] = 0;
1667 if dist_start <= 0 {
1668 self.covers[p0] = profile.value(dist) as u8;
1669 }
1670 dy += 1;
1671 }
1672
1673 self.step += 1;
1674
1675 Some(LineSpan { p0, len: p1 - p0, offset: dy as i32 })
1676 }
1677
1678 fn step_ver(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
1679 if self.step >= self.count { return None; }
1680
1681 self.li.inc();
1682 self.y += lp.inc;
1683 self.x = (lp.x1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
1684 if lp.inc > 0 { self.di.inc_y(self.x - self.old_x); }
1685 else { self.di.dec_y(self.x - self.old_x); }
1686 self.old_x = self.x;
1687
1688 let s1 = self.di.dist() / self.len;
1689 let mut dist_start = self.di.dist_start();
1690
1691 let center = MAX_HALF_WIDTH + 2;
1692 let mut p0 = center;
1693 let mut p1 = center;
1694
1695 self.covers[p1] = 0;
1696 if dist_start <= 0 {
1697 self.covers[p1] = profile.value(s1) as u8;
1698 }
1699 p1 += 1;
1700
1701 let mut dx = 1usize;
1702 loop {
1703 if dx >= DIST_SIZE { break; }
1704 let dist = self.dist[dx] - s1;
1705 if dist > self.width { break; }
1706 dist_start += self.di.dy_start();
1707 self.covers[p1] = 0;
1708 if dist_start <= 0 {
1709 self.covers[p1] = profile.value(dist) as u8;
1710 }
1711 p1 += 1;
1712 dx += 1;
1713 }
1714
1715 let mut dx = 1usize;
1716 dist_start = self.di.dist_start();
1717 loop {
1718 if dx >= DIST_SIZE { break; }
1719 let dist = self.dist[dx] + s1;
1720 if dist > self.width { break; }
1721 dist_start -= self.di.dy_start();
1722 p0 -= 1;
1723 self.covers[p0] = 0;
1724 if dist_start <= 0 {
1725 self.covers[p0] = profile.value(dist) as u8;
1726 }
1727 dx += 1;
1728 }
1729
1730 self.step += 1;
1731
1732 Some(LineSpan { p0, len: p1 - p0, offset: dx as i32 })
1733 }
1734}
1735
1736struct LineInterpolatorAa2 {
1739 di: DistanceInterpolator2,
1740 li: Dda2LineInterpolator,
1741 x: i32,
1742 y: i32,
1743 old_x: i32,
1744 old_y: i32,
1745 count: i32,
1746 width: i32,
1747 max_extent: i32,
1748 len: i32,
1749 step: i32,
1750 dist: [i32; DIST_SIZE],
1751 pub covers: [u8; COVER_SIZE],
1752}
1753
1754impl LineInterpolatorAa2 {
1755 fn new(lp: &LineParameters, ex: i32, ey: i32, subpixel_width: i32) -> Self {
1756 let (mut li, x, y, count, len, max_extent, dist) =
1757 init_line_interpolator_base(lp, subpixel_width);
1758
1759 let di = DistanceInterpolator2::new_end(
1760 lp.x1, lp.y1, lp.x2, lp.y2, ex, ey,
1761 lp.x1 & !LINE_SUBPIXEL_MASK,
1762 lp.y1 & !LINE_SUBPIXEL_MASK,
1763 );
1764
1765 li.adjust_forward();
1766 let step = 0 - max_extent;
1767
1768 Self {
1769 di, li, x, y, old_x: x, old_y: y,
1770 count, width: subpixel_width, max_extent, len, step,
1771 dist, covers: [0u8; COVER_SIZE],
1772 }
1773 }
1774
1775 fn x(&self) -> i32 { self.x }
1776 fn y(&self) -> i32 { self.y }
1777
1778 fn step_hor(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
1779 if self.step >= self.count { return None; }
1780
1781 self.li.inc();
1782 self.x += lp.inc;
1783 self.y = (lp.y1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
1784 if lp.inc > 0 { self.di.inc_x(self.y - self.old_y); }
1785 else { self.di.dec_x(self.y - self.old_y); }
1786 self.old_y = self.y;
1787
1788 let s1 = self.di.dist() / self.len;
1789 let mut dist_end = self.di.dist_end();
1790
1791 let center = MAX_HALF_WIDTH + 2;
1792 let mut p0 = center;
1793 let mut p1 = center;
1794
1795 let mut npix = 0;
1796 self.covers[p1] = 0;
1797 if dist_end > 0 {
1798 self.covers[p1] = profile.value(s1) as u8;
1799 npix += 1;
1800 }
1801 p1 += 1;
1802
1803 let mut dy = 1usize;
1804 loop {
1805 if dy >= DIST_SIZE { break; }
1806 let dist = self.dist[dy] - s1;
1807 if dist > self.width { break; }
1808 dist_end -= self.di.dx_end();
1809 self.covers[p1] = 0;
1810 if dist_end > 0 {
1811 self.covers[p1] = profile.value(dist) as u8;
1812 npix += 1;
1813 }
1814 p1 += 1;
1815 dy += 1;
1816 }
1817
1818 let mut dy = 1usize;
1819 dist_end = self.di.dist_end();
1820 loop {
1821 if dy >= DIST_SIZE { break; }
1822 let dist = self.dist[dy] + s1;
1823 if dist > self.width { break; }
1824 dist_end += self.di.dx_end();
1825 p0 -= 1;
1826 self.covers[p0] = 0;
1827 if dist_end > 0 {
1828 self.covers[p0] = profile.value(dist) as u8;
1829 npix += 1;
1830 }
1831 dy += 1;
1832 }
1833
1834 self.step += 1;
1835 if npix == 0 { return None; }
1836
1837 Some(LineSpan { p0, len: p1 - p0, offset: dy as i32 })
1838 }
1839
1840 fn step_ver(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
1841 if self.step >= self.count { return None; }
1842
1843 self.li.inc();
1844 self.y += lp.inc;
1845 self.x = (lp.x1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
1846 if lp.inc > 0 { self.di.inc_y(self.x - self.old_x); }
1847 else { self.di.dec_y(self.x - self.old_x); }
1848 self.old_x = self.x;
1849
1850 let s1 = self.di.dist() / self.len;
1851 let mut dist_end = self.di.dist_end();
1852
1853 let center = MAX_HALF_WIDTH + 2;
1854 let mut p0 = center;
1855 let mut p1 = center;
1856
1857 let mut npix = 0;
1858 self.covers[p1] = 0;
1859 if dist_end > 0 {
1860 self.covers[p1] = profile.value(s1) as u8;
1861 npix += 1;
1862 }
1863 p1 += 1;
1864
1865 let mut dx = 1usize;
1866 loop {
1867 if dx >= DIST_SIZE { break; }
1868 let dist = self.dist[dx] - s1;
1869 if dist > self.width { break; }
1870 dist_end += self.di.dy_end();
1871 self.covers[p1] = 0;
1872 if dist_end > 0 {
1873 self.covers[p1] = profile.value(dist) as u8;
1874 npix += 1;
1875 }
1876 p1 += 1;
1877 dx += 1;
1878 }
1879
1880 let mut dx = 1usize;
1881 dist_end = self.di.dist_end();
1882 loop {
1883 if dx >= DIST_SIZE { break; }
1884 let dist = self.dist[dx] + s1;
1885 if dist > self.width { break; }
1886 dist_end -= self.di.dy_end();
1887 p0 -= 1;
1888 self.covers[p0] = 0;
1889 if dist_end > 0 {
1890 self.covers[p0] = profile.value(dist) as u8;
1891 npix += 1;
1892 }
1893 dx += 1;
1894 }
1895
1896 self.step += 1;
1897 if npix == 0 { return None; }
1898
1899 Some(LineSpan { p0, len: p1 - p0, offset: dx as i32 })
1900 }
1901}
1902
1903struct LineInterpolatorAa3 {
1906 di: DistanceInterpolator3,
1907 li: Dda2LineInterpolator,
1908 x: i32,
1909 y: i32,
1910 old_x: i32,
1911 old_y: i32,
1912 count: i32,
1913 width: i32,
1914 max_extent: i32,
1915 len: i32,
1916 step: i32,
1917 dist: [i32; DIST_SIZE],
1918 pub covers: [u8; COVER_SIZE],
1919}
1920
1921impl LineInterpolatorAa3 {
1922 fn new(
1923 lp: &LineParameters,
1924 sx: i32, sy: i32, ex: i32, ey: i32,
1925 subpixel_width: i32,
1926 ) -> Self {
1927 let (mut li, mut x, mut y, count, len, max_extent, dist) =
1928 init_line_interpolator_base(lp, subpixel_width);
1929
1930 let mut di = DistanceInterpolator3::new(
1931 lp.x1, lp.y1, lp.x2, lp.y2,
1932 sx, sy, ex, ey,
1933 lp.x1 & !LINE_SUBPIXEL_MASK,
1934 lp.y1 & !LINE_SUBPIXEL_MASK,
1935 );
1936
1937 let mut old_x = x;
1938 let mut old_y = y;
1939 let mut step = 0i32;
1940
1941 let mut npix = 1i32;
1943
1944 if lp.vertical {
1945 loop {
1946 li.dec();
1947 y -= lp.inc;
1948 x = (lp.x1 + li.y()) >> LINE_SUBPIXEL_SHIFT;
1949
1950 if lp.inc > 0 {
1951 di.dec_y(x - old_x);
1952 } else {
1953 di.inc_y(x - old_x);
1954 }
1955 old_x = x;
1956
1957 let mut dist1_start = di.dist_start();
1958 let mut dist2_start = dist1_start;
1959
1960 let mut dx = 0;
1961 if dist1_start < 0 { npix += 1; }
1962 loop {
1963 dist1_start += di.dy_start();
1964 dist2_start -= di.dy_start();
1965 if dist1_start < 0 { npix += 1; }
1966 if dist2_start < 0 { npix += 1; }
1967 dx += 1;
1968 if dist[dx as usize] > subpixel_width { break; }
1969 }
1970 if npix == 0 { break; }
1971 npix = 0;
1972 step -= 1;
1973 if step < -max_extent { break; }
1974 }
1975 } else {
1976 loop {
1977 li.dec();
1978 x -= lp.inc;
1979 y = (lp.y1 + li.y()) >> LINE_SUBPIXEL_SHIFT;
1980
1981 if lp.inc > 0 {
1982 di.dec_x(y - old_y);
1983 } else {
1984 di.inc_x(y - old_y);
1985 }
1986 old_y = y;
1987
1988 let mut dist1_start = di.dist_start();
1989 let mut dist2_start = dist1_start;
1990
1991 let mut dy = 0;
1992 if dist1_start < 0 { npix += 1; }
1993 loop {
1994 dist1_start -= di.dx_start();
1995 dist2_start += di.dx_start();
1996 if dist1_start < 0 { npix += 1; }
1997 if dist2_start < 0 { npix += 1; }
1998 dy += 1;
1999 if dist[dy as usize] > subpixel_width { break; }
2000 }
2001 if npix == 0 { break; }
2002 npix = 0;
2003 step -= 1;
2004 if step < -max_extent { break; }
2005 }
2006 }
2007
2008 li.adjust_forward();
2009 step -= max_extent;
2010
2011 Self {
2012 di, li, x, y, old_x, old_y,
2013 count, width: subpixel_width, max_extent, len, step,
2014 dist, covers: [0u8; COVER_SIZE],
2015 }
2016 }
2017
2018 fn x(&self) -> i32 { self.x }
2019 fn y(&self) -> i32 { self.y }
2020
2021 fn step_hor(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
2022 if self.step >= self.count { return None; }
2023
2024 self.li.inc();
2025 self.x += lp.inc;
2026 self.y = (lp.y1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
2027 if lp.inc > 0 { self.di.inc_x(self.y - self.old_y); }
2028 else { self.di.dec_x(self.y - self.old_y); }
2029 self.old_y = self.y;
2030
2031 let s1 = self.di.dist() / self.len;
2032 let mut dist_start = self.di.dist_start();
2033 let mut dist_end = self.di.dist_end();
2034
2035 let center = MAX_HALF_WIDTH + 2;
2036 let mut p0 = center;
2037 let mut p1 = center;
2038
2039 let mut npix = 0;
2040 self.covers[p1] = 0;
2041 if dist_end > 0 {
2042 if dist_start <= 0 {
2043 self.covers[p1] = profile.value(s1) as u8;
2044 }
2045 npix += 1;
2046 }
2047 p1 += 1;
2048
2049 let mut dy = 1usize;
2050 loop {
2051 if dy >= DIST_SIZE { break; }
2052 let dist = self.dist[dy] - s1;
2053 if dist > self.width { break; }
2054 dist_start -= self.di.dx_start();
2055 dist_end -= self.di.dx_end();
2056 self.covers[p1] = 0;
2057 if dist_end > 0 && dist_start <= 0 {
2058 self.covers[p1] = profile.value(dist) as u8;
2059 npix += 1;
2060 }
2061 p1 += 1;
2062 dy += 1;
2063 }
2064
2065 let mut dy = 1usize;
2066 dist_start = self.di.dist_start();
2067 dist_end = self.di.dist_end();
2068 loop {
2069 if dy >= DIST_SIZE { break; }
2070 let dist = self.dist[dy] + s1;
2071 if dist > self.width { break; }
2072 dist_start += self.di.dx_start();
2073 dist_end += self.di.dx_end();
2074 p0 -= 1;
2075 self.covers[p0] = 0;
2076 if dist_end > 0 && dist_start <= 0 {
2077 self.covers[p0] = profile.value(dist) as u8;
2078 npix += 1;
2079 }
2080 dy += 1;
2081 }
2082
2083 self.step += 1;
2084 if npix == 0 { return None; }
2085
2086 Some(LineSpan { p0, len: p1 - p0, offset: dy as i32 })
2087 }
2088
2089 fn step_ver(&mut self, profile: &LineProfileAa, lp: &LineParameters) -> Option<LineSpan> {
2090 if self.step >= self.count { return None; }
2091
2092 self.li.inc();
2093 self.y += lp.inc;
2094 self.x = (lp.x1 + self.li.y()) >> LINE_SUBPIXEL_SHIFT;
2095 if lp.inc > 0 { self.di.inc_y(self.x - self.old_x); }
2096 else { self.di.dec_y(self.x - self.old_x); }
2097 self.old_x = self.x;
2098
2099 let s1 = self.di.dist() / self.len;
2100 let mut dist_start = self.di.dist_start();
2101 let mut dist_end = self.di.dist_end();
2102
2103 let center = MAX_HALF_WIDTH + 2;
2104 let mut p0 = center;
2105 let mut p1 = center;
2106
2107 let mut npix = 0;
2108 self.covers[p1] = 0;
2109 if dist_end > 0 {
2110 if dist_start <= 0 {
2111 self.covers[p1] = profile.value(s1) as u8;
2112 }
2113 npix += 1;
2114 }
2115 p1 += 1;
2116
2117 let mut dx = 1usize;
2118 loop {
2119 if dx >= DIST_SIZE { break; }
2120 let dist = self.dist[dx] - s1;
2121 if dist > self.width { break; }
2122 dist_start += self.di.dy_start();
2123 dist_end += self.di.dy_end();
2124 self.covers[p1] = 0;
2125 if dist_end > 0 && dist_start <= 0 {
2126 self.covers[p1] = profile.value(dist) as u8;
2127 npix += 1;
2128 }
2129 p1 += 1;
2130 dx += 1;
2131 }
2132
2133 let mut dx = 1usize;
2134 dist_start = self.di.dist_start();
2135 dist_end = self.di.dist_end();
2136 loop {
2137 if dx >= DIST_SIZE { break; }
2138 let dist = self.dist[dx] + s1;
2139 if dist > self.width { break; }
2140 dist_start -= self.di.dy_start();
2141 dist_end -= self.di.dy_end();
2142 p0 -= 1;
2143 self.covers[p0] = 0;
2144 if dist_end > 0 && dist_start <= 0 {
2145 self.covers[p0] = profile.value(dist) as u8;
2146 npix += 1;
2147 }
2148 dx += 1;
2149 }
2150
2151 self.step += 1;
2152 if npix == 0 { return None; }
2153
2154 Some(LineSpan { p0, len: p1 - p0, offset: dx as i32 })
2155 }
2156}
2157
2158#[cfg(test)]
2163mod tests {
2164 use super::*;
2165 use crate::color::Rgba8;
2166 use crate::pixfmt_rgba::PixfmtRgba32;
2167 use crate::rendering_buffer::RowAccessor;
2168
2169 fn make_buffer(w: u32, h: u32) -> (Vec<u8>, RowAccessor) {
2170 let stride = (w * 4) as i32;
2171 let buf = vec![0u8; (h * w * 4) as usize];
2172 let mut ra = RowAccessor::new();
2173 unsafe {
2174 ra.attach(buf.as_ptr() as *mut u8, w, h, stride);
2175 }
2176 (buf, ra)
2177 }
2178
2179 #[test]
2180 fn test_line_profile_creation() {
2181 let p = LineProfileAa::with_width(2.0);
2182 assert!(p.subpixel_width() > 0);
2183 assert!(p.profile_size() > 0);
2184 }
2185
2186 #[test]
2187 fn test_line_profile_value_center() {
2188 let p = LineProfileAa::with_width(3.0);
2189 let center = p.value(0);
2191 assert!(center > 200, "center coverage={center} should be > 200");
2192 }
2193
2194 #[test]
2195 fn test_line_profile_value_edge() {
2196 let p = LineProfileAa::with_width(3.0);
2197 let far = p.value(800);
2200 assert_eq!(far, 0);
2201 }
2202
2203 #[test]
2204 fn test_distance_interpolator1() {
2205 let di = DistanceInterpolator1::new(0, 0, 256, 0, 128, 128);
2206 assert_ne!(di.dist(), 0);
2209 }
2210
2211 #[test]
2212 fn test_render_line0() {
2213 let (_buf, mut ra) = make_buffer(100, 100);
2214 let pixf = PixfmtRgba32::new(&mut ra);
2215 let mut ren = RendererBase::new(pixf);
2216 let prof = LineProfileAa::with_width(2.0);
2217 let mut ren_aa = RendererOutlineAa::new(&mut ren, &prof);
2218 ren_aa.set_color(Rgba8::new(255, 0, 0, 255));
2219
2220 let lp = LineParameters::new(
2222 10 * 256, 50 * 256,
2223 90 * 256, 50 * 256,
2224 80 * 256,
2225 );
2226 ren_aa.line0(&lp);
2227
2228 let mut found = false;
2230 for y in 48..=52 {
2231 for x in 0..100 {
2232 let p = ren_aa.ren().pixel(x, y);
2233 if p.r > 0 {
2234 found = true;
2235 break;
2236 }
2237 }
2238 if found { break; }
2239 }
2240 assert!(found, "Expected red pixels near row 50");
2241 }
2242
2243 #[test]
2244 fn test_render_line_diagonal() {
2245 let (_buf, mut ra) = make_buffer(100, 100);
2246 let pixf = PixfmtRgba32::new(&mut ra);
2247 let mut ren = RendererBase::new(pixf);
2248 let prof = LineProfileAa::with_width(1.5);
2249 let mut ren_aa = RendererOutlineAa::new(&mut ren, &prof);
2250 ren_aa.set_color(Rgba8::new(0, 255, 0, 255));
2251
2252 let lp = LineParameters::new(
2253 10 * 256, 10 * 256,
2254 90 * 256, 90 * 256,
2255 uround(calc_distance_i(10 * 256, 10 * 256, 90 * 256, 90 * 256)),
2256 );
2257 ren_aa.line0(&lp);
2258
2259 let p = ren_aa.ren().pixel(50, 50);
2260 assert!(p.g > 0, "Expected green pixel at (50,50), got g={}", p.g);
2261 }
2262}