ytesrev/utils/
mod.rs

1//! Different utilities for drawing
2
3use std::mem;
4
5use sdl2::rect::Point;
6use sdl2::render::{BlendMode, Canvas};
7use sdl2::video::Window;
8
9const EPSILON: f64 = 0.0001;
10
11/// Draw an antialiased line. Uses circles as caps
12pub fn line_aa(canvas: &mut Canvas<Window>, start: (f64, f64), end: (f64, f64)) {
13    line_aa_width(canvas, start, end, 1.);
14}
15
16/// Draw an antialiased circle.
17pub fn circle_aa(canvas: &mut Canvas<Window>, center: (f64, f64), rad: f64) {
18    line_aa_width(canvas, center, center, rad);
19}
20
21/// Draw an antialiased line with a specified line width
22pub 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        // Fill filled points
116        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}