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