1use std::slice;
2use std::ptr;
3
4use super::Color;
5use super::space::*;
6
7pub struct Buffer<'a> {
8 buf: &'a mut [Color],
9 width: usize,
10 height: usize,
11}
12
13impl<'a> Buffer<'a> {
14 pub fn from_row(ptr: *mut Color, len: usize, width: usize) -> Self {
15 if len % width != 0 {
16 unreachable!()
17 }
18 Buffer {
19 buf: unsafe { slice::from_raw_parts_mut(ptr, len) },
20 width,
21 height: len / width,
22 }
23 }
24
25 pub fn height(&self) -> usize {
26 self.height
27 }
28
29 pub fn width(&self) -> usize {
30 self.width
31 }
32
33 pub fn len(&self) -> usize {
34 self.buf.len()
35 }
36
37 pub fn clear(&mut self, color: Color) {
38 unsafe {
39 ptr::copy(&color, self.buf.as_mut_ptr(), self.buf.len());
40 }
41 }
42
43 pub fn fade(&mut self, k: u8) {
44 for pixel in self.buf.iter_mut() {
45 pixel.a = (pixel.a as u16 * k as u16 / 256) as u8;
46 }
47 }
48
49 pub fn point(&mut self, x: isize, y: isize, color: Color) {
50 if clip_value(x, 0, self.width as isize).is_fixed() ||
51 clip_value(y, 0, self.height as isize).is_fixed()
52 {
53 return;
54 }
55 self.unchecked_point(x as usize, y as usize, color);
56 }
57
58 #[inline]
59 pub fn unchecked_point(&mut self, x: usize, y: usize, color: Color) {
60 self.buf[y * self.width + x] = color;
61 }
62
63 pub fn bar<R>(&mut self, rect: R, color: Color)
64 where R: Into<Rect<isize>>
65 {
66 let (rect, _is_clipped) = rect.into()
67 .clip(((0, 0), (self.width as isize, self.height as isize)))
68 .into_inner_checked();
69
70 if rect.is_collapsed() {
71 return;
72 }
73
74 let (left, top) = (rect.a.x as usize, rect.a.y as usize);
75 let (right, bottom) = (rect.b.x as usize, rect.b.y as usize);
76 let width = right - left;
77
78 let mut start = top * self.width + left;
79 for _ in top .. bottom {
80 for v in &mut self.buf[start .. start + width] {
81 *v = color;
82 }
83 start += self.width;
84 }
85 }
86
87 pub fn line<PA, PB>(&mut self, a: PA, b: PB, color: Color)
89 where
90 PA: Into<Point<isize>>,
91 PB: Into<Point<isize>>,
92 {
93 let (a, b) = (a.into(), b.into());
94
95 if a.x == b.x || a.y == b.y {
96 self.bar((a, b), color);
97 }
98
99 let (a, b) =
100 if a.x > b.x { (b, a) } else { (a, b) };
101
102 let (transpose, a, b) =
103 if (b.y - a.y).abs() > (b.x - a.x).abs() {
104 (true, a.transpose(), b.transpose())
105 } else {
106 (false, a, b)
107 };
108
109 let (a, b) =
110 if a.x > b.x { (b, a) } else { (a, b) };
111
112 debug_assert!(b.x >= a.x);
113
114 let dx = b.x - a.x;
115 let dy = b.y - a.y;
116
117 let (sy, sd) = if dy > 0 {
120 (1, 2 * dy)
121 } else {
122 (-1, - 2 * dy)
123 };
124
125 let mut d: isize = sd - dx;
126 let mut y: isize = a.y;
127
128 for x in a.x .. b.x {
129 let (tx, ty) = if transpose { (y, x) } else { (x, y) };
130 self.point(tx, ty, color);
131 if d > 0 {
132 y += sy;
133 d -= 2 * dx;
134 }
135 d += sd;
136 }
137 }
138
139 pub fn rect(&mut self, x1: isize, y1: isize, x2: isize, y2: isize, color: Color) {
140 let x1 = clip_value(x1, 0, self.width as isize).into_inner();
141 let x2 = clip_value(x2, 0, self.width as isize).into_inner();
142 if x1 == x2 {
143 return;
144 }
145 let y1 = clip_value(y1, 0, self.height as isize).into_inner();
146 let y2 = clip_value(y2, 0, self.height as isize).into_inner();
147 if y1 == y2 {
148 return;
149 }
150
151 let (left, right) = sort(x1 as usize, x2 as usize).into_inner();
152 let (top, bottom) = sort(y1 as usize, y2 as usize).into_inner();
153 let (right_1, bottom_1) = (right - 1, bottom - 1);
154
155 for x in left .. right {
156 self.unchecked_point(x, top, color);
157 }
158 if bottom_1 != top {
159 for x in left .. right {
160 self.unchecked_point(x, bottom_1, color);
161 }
162 }
163 for y in top .. bottom {
164 self.unchecked_point(left, y, color);
165 }
166 if right_1 != left {
167 for y in top .. bottom {
168 self.unchecked_point(right_1, y, color);
169 }
170 }
171 }
172}