1use crate::basics::CoverType;
11use crate::color::Gray8;
12use crate::pixfmt_rgba::PixelFormat;
13use crate::rendering_buffer::RowAccessor;
14
15const BPP: usize = 1;
17
18pub struct PixfmtGray8<'a> {
27 rbuf: &'a mut RowAccessor,
28}
29
30impl<'a> PixfmtGray8<'a> {
31 pub fn new(rbuf: &'a mut RowAccessor) -> Self {
32 Self { rbuf }
33 }
34
35 #[inline]
37 fn row(&self, y: i32) -> &[u8] {
38 unsafe {
39 let ptr = self.rbuf.row_ptr(y);
40 std::slice::from_raw_parts(ptr, self.rbuf.width() as usize * BPP)
41 }
42 }
43
44 #[inline]
46 fn row_mut(&mut self, y: i32) -> &mut [u8] {
47 unsafe {
48 let ptr = self.rbuf.row_ptr(y);
49 std::slice::from_raw_parts_mut(ptr, self.rbuf.width() as usize * BPP)
50 }
51 }
52
53 pub fn clear(&mut self, c: &Gray8) {
55 let h = self.rbuf.height();
56 for y in 0..h {
57 let row = self.row_mut(y as i32);
58 for px in row.iter_mut() {
59 *px = c.v;
60 }
61 }
62 }
63
64 #[inline]
66 fn blend_pix(p: &mut u8, cv: u8, alpha: u8) {
67 *p = Gray8::lerp(*p, cv, alpha);
68 }
69}
70
71impl<'a> PixelFormat for PixfmtGray8<'a> {
72 type ColorType = Gray8;
73
74 fn width(&self) -> u32 {
75 self.rbuf.width()
76 }
77
78 fn height(&self) -> u32 {
79 self.rbuf.height()
80 }
81
82 fn pixel(&self, x: i32, y: i32) -> Gray8 {
83 let row = self.row(y);
84 Gray8::new(row[x as usize] as u32, 255)
85 }
86
87 fn copy_pixel(&mut self, x: i32, y: i32, c: &Gray8) {
88 let row = self.row_mut(y);
89 row[x as usize] = c.v;
90 }
91
92 fn copy_hline(&mut self, x: i32, y: i32, len: u32, c: &Gray8) {
93 let row = self.row_mut(y);
94 for i in 0..len as usize {
95 row[x as usize + i] = c.v;
96 }
97 }
98
99 fn blend_pixel(&mut self, x: i32, y: i32, c: &Gray8, cover: CoverType) {
100 let row = self.row_mut(y);
101 let alpha = Gray8::mult_cover(c.a, cover);
102 if alpha == 255 {
103 row[x as usize] = c.v;
104 } else if alpha > 0 {
105 Self::blend_pix(&mut row[x as usize], c.v, alpha);
106 }
107 }
108
109 fn blend_hline(&mut self, x: i32, y: i32, len: u32, c: &Gray8, cover: CoverType) {
110 let row = self.row_mut(y);
111 let alpha = Gray8::mult_cover(c.a, cover);
112 if alpha == 255 {
113 for i in 0..len as usize {
114 row[x as usize + i] = c.v;
115 }
116 } else if alpha > 0 {
117 for i in 0..len as usize {
118 Self::blend_pix(&mut row[x as usize + i], c.v, alpha);
119 }
120 }
121 }
122
123 fn blend_solid_hspan(&mut self, x: i32, y: i32, len: u32, c: &Gray8, covers: &[CoverType]) {
124 let row = self.row_mut(y);
125 for (i, &cov) in covers.iter().enumerate().take(len as usize) {
126 let alpha = Gray8::mult_cover(c.a, cov);
127 if alpha == 255 {
128 row[x as usize + i] = c.v;
129 } else if alpha > 0 {
130 Self::blend_pix(&mut row[x as usize + i], c.v, alpha);
131 }
132 }
133 }
134
135 fn blend_color_hspan(
136 &mut self,
137 x: i32,
138 y: i32,
139 len: u32,
140 colors: &[Gray8],
141 covers: &[CoverType],
142 cover: CoverType,
143 ) {
144 let row = self.row_mut(y);
145 if !covers.is_empty() {
146 for i in 0..len as usize {
147 let c = &colors[i];
148 let alpha = Gray8::mult_cover(c.a, covers[i]);
149 if alpha == 255 {
150 row[x as usize + i] = c.v;
151 } else if alpha > 0 {
152 Self::blend_pix(&mut row[x as usize + i], c.v, alpha);
153 }
154 }
155 } else if cover == 255 {
156 for (i, c) in colors.iter().enumerate().take(len as usize) {
157 if c.a == 255 {
158 row[x as usize + i] = c.v;
159 } else if c.a > 0 {
160 Self::blend_pix(&mut row[x as usize + i], c.v, c.a);
161 }
162 }
163 } else {
164 for (i, c) in colors.iter().enumerate().take(len as usize) {
165 let alpha = Gray8::mult_cover(c.a, cover);
166 if alpha == 255 {
167 row[x as usize + i] = c.v;
168 } else if alpha > 0 {
169 Self::blend_pix(&mut row[x as usize + i], c.v, alpha);
170 }
171 }
172 }
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179
180 fn make_buffer(w: u32, h: u32) -> (Vec<u8>, RowAccessor) {
181 let stride = w as i32;
182 let buf = vec![0u8; (h * w) as usize];
183 let mut ra = RowAccessor::new();
184 unsafe {
185 ra.attach(buf.as_ptr() as *mut u8, w, h, stride);
186 }
187 (buf, ra)
188 }
189
190 #[test]
191 fn test_new() {
192 let (_buf, mut ra) = make_buffer(100, 100);
193 let pf = PixfmtGray8::new(&mut ra);
194 assert_eq!(pf.width(), 100);
195 assert_eq!(pf.height(), 100);
196 }
197
198 #[test]
199 fn test_copy_pixel() {
200 let (_buf, mut ra) = make_buffer(10, 10);
201 let mut pf = PixfmtGray8::new(&mut ra);
202 let white = Gray8::new(255, 255);
203 pf.copy_pixel(5, 5, &white);
204 let p = pf.pixel(5, 5);
205 assert_eq!(p.v, 255);
206 assert_eq!(p.a, 255);
207 }
208
209 #[test]
210 fn test_copy_hline() {
211 let (_buf, mut ra) = make_buffer(20, 10);
212 let mut pf = PixfmtGray8::new(&mut ra);
213 let mid = Gray8::new(128, 255);
214 pf.copy_hline(5, 3, 10, &mid);
215 for x in 5..15 {
216 let p = pf.pixel(x, 3);
217 assert_eq!(p.v, 128);
218 }
219 let p = pf.pixel(4, 3);
220 assert_eq!(p.v, 0);
221 }
222
223 #[test]
224 fn test_blend_pixel_opaque() {
225 let (_buf, mut ra) = make_buffer(10, 10);
226 let mut pf = PixfmtGray8::new(&mut ra);
227 let c = Gray8::new(200, 255);
228 pf.blend_pixel(3, 3, &c, 255);
229 let p = pf.pixel(3, 3);
230 assert_eq!(p.v, 200);
231 }
232
233 #[test]
234 fn test_blend_pixel_semitransparent() {
235 let (_buf, mut ra) = make_buffer(10, 10);
236 let mut pf = PixfmtGray8::new(&mut ra);
237 let white = Gray8::new(255, 255);
239 pf.copy_hline(0, 0, 10, &white);
240
241 let black_50 = Gray8::new(0, 128);
243 pf.blend_pixel(5, 0, &black_50, 255);
244 let p = pf.pixel(5, 0);
245 assert!(p.v > 120 && p.v < 140, "v={}", p.v);
247 }
248
249 #[test]
250 fn test_blend_hline() {
251 let (_buf, mut ra) = make_buffer(20, 10);
252 let mut pf = PixfmtGray8::new(&mut ra);
253 let c = Gray8::new(100, 255);
254 pf.blend_hline(2, 2, 5, &c, 255);
255 for x in 2..7 {
256 let p = pf.pixel(x, 2);
257 assert_eq!(p.v, 100);
258 }
259 }
260
261 #[test]
262 fn test_blend_solid_hspan() {
263 let (_buf, mut ra) = make_buffer(20, 10);
264 let mut pf = PixfmtGray8::new(&mut ra);
265 let c = Gray8::new(200, 255);
266 let covers = [255u8, 128, 64, 0];
267 pf.blend_solid_hspan(0, 0, 4, &c, &covers);
268
269 let p0 = pf.pixel(0, 0);
270 assert_eq!(p0.v, 200); let p3 = pf.pixel(3, 0);
273 assert_eq!(p3.v, 0); }
275
276 #[test]
277 fn test_clear() {
278 let (_buf, mut ra) = make_buffer(10, 10);
279 let mut pf = PixfmtGray8::new(&mut ra);
280 pf.clear(&Gray8::new(128, 255));
281 let p = pf.pixel(5, 5);
282 assert_eq!(p.v, 128);
283 }
284
285 #[test]
286 fn test_pixel_always_opaque() {
287 let (_buf, mut ra) = make_buffer(10, 10);
288 let pf = PixfmtGray8::new(&mut ra);
289 let p = pf.pixel(0, 0);
290 assert_eq!(p.a, 255);
291 }
292
293 #[test]
294 fn test_blend_color_hspan_with_covers() {
295 let (_buf, mut ra) = make_buffer(20, 10);
296 let mut pf = PixfmtGray8::new(&mut ra);
297 let colors = [
298 Gray8::new(100, 255),
299 Gray8::new(200, 255),
300 Gray8::new(50, 128),
301 ];
302 let covers = [255u8, 255, 255];
303 pf.blend_color_hspan(0, 0, 3, &colors, &covers, 255);
304
305 assert_eq!(pf.pixel(0, 0).v, 100);
306 assert_eq!(pf.pixel(1, 0).v, 200);
307 let p2 = pf.pixel(2, 0);
309 assert!(p2.v > 20 && p2.v < 35, "v={}", p2.v);
310 }
311}