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