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