1use rgb::{RGBA, FromSlice};
2use super::PixelArray;
3
4#[derive(Copy, Clone, Debug)]
6#[repr(transparent)]
7pub struct EightPixels([u16; 32]);
8
9impl EightPixels {
10 pub fn new(src: &[u8]) -> Self {
12 let mut array = [0; 32];
13 array[..src.len()].copy_from_slice(src);
14 Self(array.map(|item| item as u16))
15 }
16
17 pub fn write(&self, dst: &mut [u8]) {
19 dst.copy_from_slice(&self.0.map(|item| item as u8)[..dst.len()]);
20 }
21}
22
23#[derive(Debug, Copy, Clone, PartialEq, Eq)]
25#[repr(usize)]
26pub enum AlphaConfig {
27 FirstByte,
28 SecondByte,
29 ThirdByte,
30 FourthByte,
31 None,
33}
34
35#[inline(always)]
37pub fn blend8(
38 src: EightPixels,
39 dst: &mut [u8],
40 alpha_config: AlphaConfig,
41) {
42 let result = if alpha_config != AlphaConfig::None {
43 let dst_p = EightPixels::new(dst);
44
45 let alpha_channel = match alpha_config {
46 AlphaConfig::FirstByte => 0,
47 AlphaConfig::SecondByte => 1,
48 AlphaConfig::ThirdByte => 2,
49 AlphaConfig::FourthByte => 3,
50 _ => unreachable!(),
51 };
52 let u8_max = u8::MAX as u16;
53
54 let mut result = [0; 32];
55 for i in 0..32 {
56 let p = i & !3;
57 let src_a = src.0[p + alpha_channel];
58 let dst_a = u8_max - src_a;
59 result[i] = ((src.0[i] * src_a) + (dst_p.0[i] * dst_a)) / u8_max;
60 }
61
62 EightPixels(result)
63 } else {
64 src
65 };
66
67 result.write(dst);
68}
69
70pub struct SsaaCoords<const SSAA_SQ: usize> {
72 src_o: [[usize; 8]; SSAA_SQ],
73 src_x: [[usize; 8]; SSAA_SQ],
74 src_y: [[usize; 8]; SSAA_SQ],
75}
76
77impl<const SSAA_SQ: usize> SsaaCoords<SSAA_SQ> {
78 pub fn new() -> Self {
79 const FULL_USIZE_MAX: [usize; 8] = [usize::MAX; 8];
80 Self {
81 src_o: [FULL_USIZE_MAX; SSAA_SQ],
82 src_x: [FULL_USIZE_MAX; SSAA_SQ],
83 src_y: [FULL_USIZE_MAX; SSAA_SQ],
84 }
85 }
86
87 #[inline(always)]
89 pub fn set(&mut self, pixel: usize, sub_pixel: usize, x: usize, y: usize) {
90 assert!(pixel < 8);
91 self.src_o[sub_pixel][pixel] = pixel;
92 self.src_x[sub_pixel][pixel] = x;
93 self.src_y[sub_pixel][pixel] = y;
94 }
95}
96
97#[inline(always)]
99pub fn ssaa8<P: PixelArray, const SSAA_SQ: usize>(
100 src_coords: SsaaCoords<SSAA_SQ>,
101 src: &P,
102) -> EightPixels {
103 let src_w = src.width();
104 let src_h = src.height();
105 let src_l = src.length();
106
107 let mut ssaa_px = [0; 8];
110 let mut result = EightPixels::new(&[]);
111
112 for i in 0..SSAA_SQ {
113 for j in 0..8 {
114 let src_o = src_coords.src_o[i][j];
115 let src_x = src_coords.src_x[i][j];
116 let src_y = src_coords.src_y[i][j];
117 let src_i = src_y * src_w + src_x;
118
119 let usable_x = src_x < src_w;
120 let usable_y = src_y < src_h;
121 let usable_l = src_i < src_l;
122 let usable = usable_x & usable_y & usable_l;
123
124 if usable {
125 let rgba: RGBA<u16> = src.get(src_i).into();
126 result.0.as_rgba_mut()[src_o] += rgba;
127 ssaa_px[src_o] += 1;
128 }
129 }
130 }
131
132 for i in 0..8 {
135 result.0.as_rgba_mut()[i] /= if true {
136 SSAA_SQ as u16
138 } else {
139 match ssaa_px[i] {
140 0 => 1,
141 n => n,
142 }
143 };
144 }
145
146 result
147}