1mod image;
2mod ion_sys;
3mod kobo1;
4mod kobo2;
5mod linuxfb_sys;
6mod mxcfb_sys;
7mod sunxi_sys;
8mod transform;
9
10use crate::color::{Color, BLACK, WHITE};
11use crate::geom::{lerp, nearest_segment_point, surface_area, Point, Rectangle};
12use crate::geom::{BorderSpec, ColorSource, CornerSpec, Vec2};
13use anyhow::Error;
14
15pub use self::image::Pixmap;
16pub use self::kobo1::KoboFramebuffer1;
17pub use self::kobo2::KoboFramebuffer2;
18
19#[derive(Debug, Copy, Clone)]
20pub struct Display {
21 pub dims: (u32, u32),
22 pub rotation: i8,
23}
24
25#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
26pub enum UpdateMode {
27 Gui,
28 Partial,
29 Full,
30 Fast,
31 FastMono,
32}
33
34pub trait Framebuffer {
35 fn set_pixel(&mut self, x: u32, y: u32, color: Color);
36 fn set_blended_pixel(&mut self, x: u32, y: u32, color: Color, alpha: f32);
37 fn invert_region(&mut self, rect: &Rectangle);
38 fn shift_region(&mut self, rect: &Rectangle, drift: u8);
39 fn update(&mut self, rect: &Rectangle, mode: UpdateMode) -> Result<u32, Error>;
40 fn wait(&self, token: u32) -> Result<i32, Error>;
41 fn save(&self, path: &str) -> Result<(), Error>;
42 fn set_rotation(&mut self, n: i8) -> Result<(u32, u32), Error>;
43 fn set_monochrome(&mut self, enable: bool);
44 fn set_dithered(&mut self, enable: bool);
45 fn set_inverted(&mut self, enable: bool);
46 fn monochrome(&self) -> bool;
47 fn dithered(&self) -> bool;
48 fn inverted(&self) -> bool;
49 fn width(&self) -> u32;
50 fn height(&self) -> u32;
51
52 fn toggle_inverted(&mut self) {
53 self.set_inverted(!self.inverted());
54 }
55
56 fn toggle_monochrome(&mut self) {
57 self.set_monochrome(!self.monochrome());
58 }
59
60 fn toggle_dithered(&mut self) {
61 self.set_dithered(!self.dithered());
62 }
63
64 fn rotation(&self) -> i8 {
65 0
66 }
67
68 fn dims(&self) -> (u32, u32) {
69 (self.width(), self.height())
70 }
71
72 fn rect(&self) -> Rectangle {
73 let (width, height) = self.dims();
74 rect![0, 0, width as i32, height as i32]
75 }
76
77 fn clear(&mut self, color: Color) {
78 let rect = self.rect();
79 self.draw_rectangle(&rect, color);
80 }
81
82 fn draw_rectangle(&mut self, rect: &Rectangle, color: Color) {
83 for y in rect.min.y..rect.max.y {
84 for x in rect.min.x..rect.max.x {
85 self.set_pixel(x as u32, y as u32, color);
86 }
87 }
88 }
89
90 fn draw_blended_rectangle(&mut self, rect: &Rectangle, color: Color, alpha: f32) {
91 for y in rect.min.y..rect.max.y {
92 for x in rect.min.x..rect.max.x {
93 self.set_blended_pixel(x as u32, y as u32, color, alpha);
94 }
95 }
96 }
97
98 fn draw_rectangle_outline(&mut self, rect: &Rectangle, border: &BorderSpec) {
99 let BorderSpec {
100 thickness: border_thickness,
101 color: border_color,
102 } = *border;
103 self.draw_rectangle(
104 &rect![
105 rect.min.x,
106 rect.min.y,
107 rect.max.x - border_thickness as i32,
108 rect.min.y + border_thickness as i32
109 ],
110 border_color,
111 );
112 self.draw_rectangle(
113 &rect![
114 rect.max.x - border_thickness as i32,
115 rect.min.y,
116 rect.max.x,
117 rect.max.y - border_thickness as i32
118 ],
119 border_color,
120 );
121 self.draw_rectangle(
122 &rect![
123 rect.min.x + border_thickness as i32,
124 rect.max.y - border_thickness as i32,
125 rect.max.x,
126 rect.max.y
127 ],
128 border_color,
129 );
130 self.draw_rectangle(
131 &rect![
132 rect.min.x,
133 rect.min.y + border_thickness as i32,
134 rect.min.x + border_thickness as i32,
135 rect.max.y
136 ],
137 border_color,
138 );
139 }
140
141 fn draw_pixmap(&mut self, pixmap: &Pixmap, pt: Point) {
142 for y in 0..pixmap.height {
143 for x in 0..pixmap.width {
144 let px = x + pt.x as u32;
145 let py = y + pt.y as u32;
146 let color = pixmap.get_pixel(x, y);
147 self.set_pixel(px, py, color);
148 }
149 }
150 }
151
152 fn draw_framed_pixmap(&mut self, pixmap: &Pixmap, rect: &Rectangle, pt: Point) {
153 for y in rect.min.y..rect.max.y {
154 for x in rect.min.x..rect.max.x {
155 let px = x - rect.min.x + pt.x;
156 let py = y - rect.min.y + pt.y;
157 let color = pixmap.get_pixel(x as u32, y as u32);
158 self.set_pixel(px as u32, py as u32, color);
159 }
160 }
161 }
162
163 fn draw_framed_pixmap_contrast(
164 &mut self,
165 pixmap: &Pixmap,
166 rect: &Rectangle,
167 pt: Point,
168 exponent: f32,
169 gray: f32,
170 ) {
171 if (exponent - 1.0).abs() < f32::EPSILON {
172 self.draw_framed_pixmap(pixmap, rect, pt);
173 return;
174 }
175 let rem_gray = 255.0 - gray;
176 let inv_exponent = 1.0 / exponent;
177 for y in rect.min.y..rect.max.y {
178 for x in rect.min.x..rect.max.x {
179 let px = x - rect.min.x + pt.x;
180 let py = y - rect.min.y + pt.y;
181 let raw_color = pixmap.get_pixel(x as u32, y as u32);
182 let color = raw_color.apply(|comp| {
183 let c = comp as f32;
184 if c < gray {
185 (gray * (c / gray).powf(exponent)) as u8
186 } else if c > gray {
187 (gray + rem_gray * ((c - gray) / rem_gray).powf(inv_exponent)) as u8
188 } else {
189 gray as u8
190 }
191 });
192 self.set_pixel(px as u32, py as u32, color);
193 }
194 }
195 }
196
197 fn draw_framed_pixmap_halftone(&mut self, pixmap: &Pixmap, rect: &Rectangle, pt: Point) {
198 for y in rect.min.y..rect.max.y {
199 for x in rect.min.x..rect.max.x {
200 let px = x - rect.min.x + pt.x;
201 let py = y - rect.min.y + pt.y;
202 let source_color = pixmap.get_pixel(x as u32, y as u32);
203 let color = if source_color == BLACK {
204 BLACK
205 } else if source_color == WHITE {
206 WHITE
207 } else {
208 transform::transform_dither_g2(x as u32, y as u32, source_color)
209 };
210 self.set_pixel(px as u32, py as u32, color);
211 }
212 }
213 }
214
215 fn draw_blended_pixmap(&mut self, pixmap: &Pixmap, pt: Point, color: Color) {
216 for y in 0..pixmap.height {
217 for x in 0..pixmap.width {
218 let px = x + pt.x as u32;
219 let py = y + pt.y as u32;
220 let alpha = (255.0 - pixmap.get_pixel(x, y).gray() as f32) / 255.0;
221 self.set_blended_pixel(px as u32, py as u32, color, alpha);
222 }
223 }
224 }
225
226 fn draw_rounded_rectangle(&mut self, rect: &Rectangle, corners: &CornerSpec, color: Color) {
227 let (nw, ne, se, sw) = match *corners {
228 CornerSpec::Uniform(v) => (v, v, v, v),
229 CornerSpec::North(v) => (v, v, 0, 0),
230 CornerSpec::East(v) => (0, v, v, 0),
231 CornerSpec::South(v) => (0, 0, v, v),
232 CornerSpec::West(v) => (v, 0, 0, v),
233 CornerSpec::Detailed {
234 north_west,
235 north_east,
236 south_east,
237 south_west,
238 } => (north_west, north_east, south_east, south_west),
239 };
240 let nw_c = rect.min + nw;
241 let ne_c = pt!(rect.max.x - ne, rect.min.y + ne);
242 let se_c = rect.max - se;
243 let sw_c = pt!(rect.min.x + sw, rect.max.y - sw);
244 for y in rect.min.y..rect.max.y {
245 for x in rect.min.x..rect.max.x {
246 let mut alpha = 1.0;
247 let mut pole = None;
248 if x < nw_c.x && y < nw_c.y {
249 pole = Some((nw_c, nw));
250 } else if x >= ne_c.x && y < ne_c.y {
251 pole = Some((ne_c, ne));
252 } else if x >= se_c.x && y >= se_c.y {
253 pole = Some((se_c, se));
254 } else if x < sw_c.x && y >= sw_c.y {
255 pole = Some((sw_c, sw));
256 }
257 if let Some((center, radius)) = pole {
258 let v = vec2!((x - center.x) as f32, (y - center.y) as f32) + 0.5;
259 let angle = v.angle();
260 let dist = v.length() - radius as f32;
261 alpha = surface_area(dist, angle);
262 }
263 self.set_blended_pixel(x as u32, y as u32, color, alpha);
264 }
265 }
266 }
267
268 fn draw_rounded_rectangle_with_border(
269 &mut self,
270 rect: &Rectangle,
271 corners: &CornerSpec,
272 border: &BorderSpec,
273 color: &dyn ColorSource,
274 ) {
275 let (nw, ne, se, sw) = match *corners {
276 CornerSpec::Uniform(v) => (v, v, v, v),
277 CornerSpec::North(v) => (v, v, 0, 0),
278 CornerSpec::East(v) => (0, v, v, 0),
279 CornerSpec::South(v) => (0, 0, v, v),
280 CornerSpec::West(v) => (v, 0, 0, v),
281 CornerSpec::Detailed {
282 north_west,
283 north_east,
284 south_east,
285 south_west,
286 } => (north_west, north_east, south_east, south_west),
287 };
288
289 let BorderSpec {
290 thickness: border_thickness,
291 color: border_color,
292 } = *border;
293 let nw_c = rect.min + nw;
294 let ne_c = pt!(rect.max.x - ne, rect.min.y + ne);
295 let se_c = rect.max - se;
296 let sw_c = pt!(rect.min.x + sw, rect.max.y - sw);
297
298 for y in rect.min.y..rect.max.y {
299 for x in rect.min.x..rect.max.x {
300 let mut alpha = 1.0;
301 let mut pole = None;
302 let mut color = color.color(x, y);
303 if x < nw_c.x && y < nw_c.y {
304 pole = Some((nw_c, nw));
305 } else if x >= ne_c.x && y < ne_c.y {
306 pole = Some((ne_c, ne));
307 } else if x >= se_c.x && y >= se_c.y {
308 pole = Some((se_c, se));
309 } else if x < sw_c.x && y >= sw_c.y {
310 pole = Some((sw_c, sw));
311 }
312 if let Some((center, radius)) = pole {
313 let small_radius = radius - border_thickness as i32;
314 let mid_radius = 0.5 * (radius as f32 + small_radius as f32);
315 let v = vec2!((x - center.x) as f32, (y - center.y) as f32) + 0.5;
316 let angle = v.angle();
317 let dist = v.length();
318 if dist < mid_radius {
319 let delta_dist = small_radius as f32 - dist;
320 alpha = surface_area(delta_dist, angle);
321 color = color.lerp(border_color, alpha);
322 alpha = 1.0;
323 } else {
324 let delta_dist = dist - radius as f32;
325 color = border_color;
326 alpha = surface_area(delta_dist, angle);
327 }
328 } else if x < rect.min.x + border_thickness as i32
329 || x >= rect.max.x - border_thickness as i32
330 || y < rect.min.y + border_thickness as i32
331 || y >= rect.max.y - border_thickness as i32
332 {
333 color = border_color;
334 }
335 self.set_blended_pixel(x as u32, y as u32, color, alpha);
336 }
337 }
338 }
339
340 fn draw_triangle(&mut self, triangle: &[Point], color: Color) {
341 let mut x_min = ::std::i32::MAX;
342 let mut x_max = ::std::i32::MIN;
343 let mut y_min = ::std::i32::MAX;
344 let mut y_max = ::std::i32::MIN;
345
346 for p in triangle.iter() {
347 if p.x < x_min {
348 x_min = p.x;
349 }
350 if p.x > x_max {
351 x_max = p.x;
352 }
353 if p.y < y_min {
354 y_min = p.y;
355 }
356 if p.y > y_max {
357 y_max = p.y;
358 }
359 }
360
361 x_max += 1;
362 y_max += 1;
363
364 let mut a: Vec2 = triangle[0].into();
365 let mut b: Vec2 = triangle[1].into();
366 let mut c: Vec2 = triangle[2].into();
367
368 a += 0.5;
369 b += 0.5;
370 c += 0.5;
371
372 let ab = b - a;
373 let ac = c - a;
374 let bc = c - b;
375
376 for y in y_min..y_max {
377 for x in x_min..x_max {
378 let p = vec2!(x as f32 + 0.5, y as f32 + 0.5);
379 let ap = p - a;
380 let bp = p - b;
381
382 let s_ab = ab.cross(ap).is_sign_positive();
383 let inside = ac.cross(ap).is_sign_positive() != s_ab
384 && bc.cross(bp).is_sign_positive() == s_ab;
385
386 let mut dmin = ::std::f32::MAX;
387 let mut nearest = None;
388
389 for &(u, v) in &[(a, b), (b, c), (a, c)] {
390 let (n, _) = nearest_segment_point(p, u, v);
391 let d = (n - p).length();
392 if d < dmin {
393 dmin = d;
394 nearest = Some(n);
395 }
396 }
397
398 if let Some(n) = nearest {
399 let angle = (n - p).angle();
400 let delta_dist = if inside { -dmin } else { dmin };
401 let alpha = surface_area(delta_dist, angle);
402 self.set_blended_pixel(x as u32, y as u32, color, alpha);
403 }
404 }
405 }
406 }
407
408 fn draw_disk(&mut self, center: Point, radius: i32, color: Color) {
409 let rect = Rectangle::from_disk(center, radius);
410
411 for y in rect.min.y..rect.max.y {
412 for x in rect.min.x..rect.max.x {
413 let v = vec2!((x - center.x) as f32, (y - center.y) as f32) + 0.5;
414 let angle = v.angle();
415 let delta_dist = v.length() - radius as f32;
416 let alpha = surface_area(delta_dist, angle);
417 self.set_blended_pixel(x as u32, y as u32, color, alpha);
418 }
419 }
420 }
421
422 fn draw_segment(
423 &mut self,
424 start: Point,
425 end: Point,
426 start_radius: f32,
427 end_radius: f32,
428 color: Color,
429 ) {
430 let rect = Rectangle::from_segment(
431 start,
432 end,
433 start_radius.ceil() as i32,
434 end_radius.ceil() as i32,
435 );
436 let a = vec2!(start.x as f32, start.y as f32) + 0.5;
437 let b = vec2!(end.x as f32, end.y as f32) + 0.5;
438
439 for y in rect.min.y..rect.max.y {
440 for x in rect.min.x..rect.max.x {
441 let p = vec2!(x as f32, y as f32) + 0.5;
442 let (n, t) = nearest_segment_point(p, a, b);
443 let radius = lerp(start_radius, end_radius, t);
444 if (n - p).length() <= radius {
445 self.set_pixel(x as u32, y as u32, color);
446 }
447 }
448 }
449 }
450}