1use std::mem;
4
5use sdl2::rect::Point;
6use sdl2::render::{BlendMode, Canvas};
7use sdl2::video::Window;
8
9const EPSILON: f64 = 0.0001;
10
11pub fn line_aa(canvas: &mut Canvas<Window>, start: (f64, f64), end: (f64, f64)) {
13 line_aa_width(canvas, start, end, 1.);
14}
15
16pub fn circle_aa(canvas: &mut Canvas<Window>, center: (f64, f64), rad: f64) {
18 line_aa_width(canvas, center, center, rad);
19}
20
21pub fn line_aa_width(
23 canvas: &mut Canvas<Window>,
24 mut start: (f64, f64),
25 mut end: (f64, f64),
26 line_size: f64,
27) {
28 if start == end {
29 end = (start.0 + EPSILON, start.1 + EPSILON);
30 }
31 let steep = (start.1 - end.1).abs() > (start.0 - end.0).abs();
32
33 if steep {
34 mem::swap(&mut start.0, &mut start.1);
35 mem::swap(&mut end.0, &mut end.1);
36 }
37 if start.0 > end.0 {
38 mem::swap(&mut start, &mut end);
39 }
40
41 let dx = end.0 - start.0;
42 let dy = end.1 - start.1;
43
44 let grad = dy / dx;
45
46 let line_height = line_size * (dx * dx + dy * dy).sqrt() / dx;
47
48 let half_height = line_height / 2.;
49 let half_size = line_size / 2.;
50
51 for x in (start.0 - half_size).ceil() as isize..=(end.0 + half_size) as isize {
52 let x = x as f64;
53 let x_rel = x - start.0;
54 let y_rel = x_rel * grad;
55 let y = y_rel + start.1;
56
57 let mut up = y + half_height;
58 let mut down = y - half_height;
59
60 if x_rel < half_size {
61 let y_rel_sq = half_size * half_size - x_rel * x_rel;
62 let y_rel = y_rel_sq.sqrt();
63
64 if end.1 >= start.1 {
65 if x_rel < 0. {
66 down = start.1 - y_rel;
67 }
68 if y_rel / x_rel > 1. / grad {
69 down = start.1 - y_rel;
70 }
71 if y_rel / x_rel > -1. / grad && x_rel < 0. {
72 up = start.1 + y_rel;
73 }
74 } else {
75 if x_rel < 0. {
76 up = start.1 + y_rel;
77 }
78 if y_rel / x_rel > -1. / grad {
79 up = start.1 + y_rel;
80 }
81 if y_rel / x_rel > 1. / grad && x_rel < 0. {
82 down = start.1 - y_rel;
83 }
84 }
85 }
86
87 let x_rel = x - end.0;
88 if x_rel > -half_size {
89 let y_rel_sq = half_size * half_size - x_rel * x_rel;
90 let y_rel = y_rel_sq.sqrt();
91
92 if end.1 < start.1 {
93 if x_rel >= 0. {
94 down = end.1 - y_rel;
95 }
96 if y_rel / x_rel < 1. / grad {
97 down = end.1 - y_rel;
98 }
99 if y_rel / x_rel < -1. / grad && x_rel >= 0. {
100 up = end.1 + y_rel;
101 }
102 } else {
103 if x_rel >= 0. {
104 up = end.1 + y_rel;
105 }
106 if y_rel / x_rel < -1. / grad {
107 up = end.1 + y_rel;
108 }
109 if y_rel / x_rel < 1. / grad && x_rel >= 0. {
110 down = end.1 - y_rel;
111 }
112 }
113 }
114
115 for y_ in down.ceil() as isize..up.floor() as isize {
117 put_pixel(canvas, (x, y_ as f64), 1., steep);
118 }
119
120 put_pixel(canvas, (x, up), fpart(up), steep);
121 put_pixel(canvas, (x, down), rfpart(down), steep);
122 }
123}
124
125fn put_pixel(canvas: &mut Canvas<Window>, at: (f64, f64), intensity: f64, steep: bool) {
126 let color_orig = canvas.draw_color();
127 let mut color = color_orig.clone();
128
129 canvas.set_blend_mode(BlendMode::Blend);
130
131 color.a = (intensity * color.a as f64) as u8;
132
133 canvas.set_draw_color(color);
134
135 if steep {
136 canvas
137 .draw_point(Point::new(at.1 as i32, at.0 as i32))
138 .expect("Can't draw");
139 } else {
140 canvas
141 .draw_point(Point::new(at.0 as i32, at.1 as i32))
142 .expect("Can't draw");
143 }
144
145 canvas.set_draw_color(color_orig);
146}
147
148fn fpart(x: f64) -> f64 {
149 x - x.floor() as f64
150}
151fn rfpart(x: f64) -> f64 {
152 1. - fpart(x)
153}