1use core::mem;
2
3#[inline]
4const fn interleave_and_reverse_bits(a: usize, b: usize, highest_output_bit: u32) -> usize {
5 let mut acc: usize = 0;
6 let mut bit_o: usize = 1 << highest_output_bit;
7 let mut bit_i: usize = 1;
9 loop {
10 if (a & bit_i) != 0 {
11 acc |= bit_o;
12 }
13 bit_o = bit_o.unbounded_shr(1);
14
15 if (b & bit_i) != 0 {
16 acc |= bit_o;
17 }
18 bit_o = bit_o.unbounded_shr(1);
19
20 if matches!(bit_o, 0) {
21 return acc;
22 }
23
24 bit_i = bit_i.unbounded_shl(1);
25 }
26}
27
28#[inline]
29pub const fn compute_value_at_index(i: usize, j: usize, highest_output_bit: u32) -> usize {
30 interleave_and_reverse_bits(i ^ j, i, highest_output_bit)
32}
33
34#[inline]
35pub const fn matrix<T: Copy, const N: usize, const M: usize>() -> [[T; M]; N] {
36 assert!(N > 0, "Cannot generate a zero-size Bayer dithering matrix.");
37 assert!(M > 0, "Cannot generate a zero-size Bayer dithering matrix.");
38
39 let mut uninit = [[mem::MaybeUninit::uninit(); M]; N];
40 let mut ptr = uninit.as_mut_ptr() as *mut mem::MaybeUninit<T>;
41
42 let index_bits_rounding_up = {
43 let bits_rounding_up_n = ((N << 1) - 1).ilog2();
44 let bits_rounding_up_m = ((M << 1) - 1).ilog2();
45 let mut max = if bits_rounding_up_n > bits_rounding_up_m {
46 bits_rounding_up_n
47 } else {
48 bits_rounding_up_m
49 };
50 max <<= 1;
51 if let Some(sub) = max.checked_sub(1) {
52 sub
53 } else {
54 0
55 }
56 };
57
58 let just_past_max_representable = 1_usize.checked_shl((mem::size_of::<T>() << 3) as u32);
59
60 let mut i = 0;
61 loop {
62 let mut j = 0;
63 'j: loop {
64 let entire_usize = compute_value_at_index(i, j, index_bits_rounding_up);
65
66 #[cfg(debug_assertions)]
67 if let Some(just_past_max_representable) = just_past_max_representable {
68 assert!(
69 entire_usize < just_past_max_representable,
70 "It seems that the type you're using for Bayer matrix elements is too small to hold their values."
71 );
72 }
73
74 let lower_bits = &entire_usize as *const usize as *const T;
75
76 #[cfg(target_endian = "big")]
77 {
78 lower_bits = lower_bits
79 .byte_add(const { core::mem::size_of::<usize>() - core::mem::size_of::<T>() });
80 }
81
82 let _: &mut _ = unsafe { &mut *ptr }.write(unsafe { *lower_bits });
83 if j == const { M - 1 } {
84 if i == const { N - 1 } {
85 return unsafe {
86 *(&uninit as *const [[mem::MaybeUninit<T>; M]; N] as *const [[T; M]; N])
87 };
88 }
89 break 'j;
90 }
91 ptr = unsafe { ptr.add(1) };
92 j += 1;
93 }
94 ptr = unsafe { ptr.add(1) };
95 i += 1;
96 }
97}
98
99#[cfg(test)]
100mod test {
101 use super::*;
102
103 #[test]
104 fn test_1x1() {
105 const MATRIX: [[u8; 1]; 1] = matrix();
106 assert_eq!(MATRIX, [[0]]);
107 }
108
109 #[test]
110 fn test_2x2() {
111 const MATRIX: [[u8; 2]; 2] = matrix();
112 assert_eq!(MATRIX, [[0, 2], [3, 1]]);
113 }
114
115 #[test]
116 fn test_4x4() {
117 const MATRIX: [[u8; 4]; 4] = matrix();
118 assert_eq!(
119 MATRIX,
120 [[0, 8, 2, 10], [12, 4, 14, 6], [3, 11, 1, 9], [15, 7, 13, 5]],
121 );
122 }
123
124 #[test]
125 fn test_8x8() {
126 const MATRIX: [[u8; 8]; 8] = matrix();
127 assert_eq!(
128 MATRIX,
129 [
130 [0, 32, 8, 40, 2, 34, 10, 42],
131 [48, 16, 56, 24, 50, 18, 58, 26],
132 [12, 44, 4, 36, 14, 46, 6, 38],
133 [60, 28, 52, 20, 62, 30, 54, 22],
134 [3, 35, 11, 43, 1, 33, 9, 41],
135 [51, 19, 59, 27, 49, 17, 57, 25],
136 [15, 47, 7, 39, 13, 45, 5, 37],
137 [63, 31, 55, 23, 61, 29, 53, 21]
138 ],
139 );
140 }
141
142 }