embedded_3dgfx/bsp/
coverage.rs1pub struct CoverageBuffer<'a> {
24 data: &'a mut [u8],
25 pub width: usize,
26 pub height: usize,
27}
28
29impl<'a> CoverageBuffer<'a> {
30 pub const fn bytes_for(width: usize, height: usize) -> usize {
32 (width * height + 7) / 8
33 }
34
35 pub fn new(data: &'a mut [u8], width: usize, height: usize) -> Option<Self> {
39 let needed = Self::bytes_for(width, height);
40 if data.len() < needed {
41 return None;
42 }
43 Some(Self {
44 data,
45 width,
46 height,
47 })
48 }
49
50 #[inline]
52 pub fn clear(&mut self) {
53 self.data.fill(0);
54 }
55
56 #[inline]
58 pub fn is_covered(&self, x: usize, y: usize) -> bool {
59 if x >= self.width || y >= self.height {
60 return false;
61 }
62 let idx = y * self.width + x;
63 let byte = idx >> 3;
64 let bit = idx & 7;
65 (self.data[byte] >> bit) & 1 != 0
67 }
68
69 #[inline]
71 pub fn mark_covered(&mut self, x: usize, y: usize) {
72 if x >= self.width || y >= self.height {
73 return;
74 }
75 let idx = y * self.width + x;
76 let byte = idx >> 3;
77 let bit = idx & 7;
78 self.data[byte] |= 1 << bit;
79 }
80
81 pub fn is_full(&self) -> bool {
83 let pixels = self.width * self.height;
84 let full_bytes = pixels >> 3;
85 let rem_bits = pixels & 7;
86
87 for &b in &self.data[..full_bytes] {
88 if b != 0xFF {
89 return false;
90 }
91 }
92 if rem_bits > 0 {
93 let mask = (1u8 << rem_bits) - 1;
94 let last = self.data.get(full_bytes).copied().unwrap_or(0);
95 if last & mask != mask {
96 return false;
97 }
98 }
99 true
100 }
101
102 #[cfg(feature = "std")]
105 pub fn fill_ratio(&self) -> f32 {
106 let pixels = self.width * self.height;
107 let covered = self
108 .data
109 .iter()
110 .map(|b| b.count_ones() as usize)
111 .sum::<usize>();
112 let covered = covered.min(pixels);
113 covered as f32 / pixels as f32
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 extern crate std;
120 use super::*;
121
122 #[test]
123 fn bytes_for_240x135() {
124 assert_eq!(CoverageBuffer::bytes_for(240, 135), (240 * 135 + 7) / 8);
125 }
126
127 #[test]
128 fn new_rejects_undersized_buffer() {
129 let mut buf = [0u8; 1];
130 assert!(CoverageBuffer::new(&mut buf, 240, 135).is_none());
131 }
132
133 #[test]
134 fn mark_and_query() {
135 let mut buf = [0u8; CoverageBuffer::bytes_for(8, 8)];
136 let mut cov = CoverageBuffer::new(&mut buf, 8, 8).unwrap();
137
138 assert!(!cov.is_covered(3, 2));
139 cov.mark_covered(3, 2);
140 assert!(cov.is_covered(3, 2));
141 assert!(!cov.is_covered(2, 2));
143 assert!(!cov.is_covered(4, 2));
144 assert!(!cov.is_covered(3, 1));
145 assert!(!cov.is_covered(3, 3));
146 }
147
148 #[test]
149 fn clear_resets_coverage() {
150 let mut buf = [0u8; CoverageBuffer::bytes_for(4, 4)];
151 let mut cov = CoverageBuffer::new(&mut buf, 4, 4).unwrap();
152 cov.mark_covered(1, 1);
153 assert!(cov.is_covered(1, 1));
154 cov.clear();
155 assert!(!cov.is_covered(1, 1));
156 }
157
158 #[test]
159 fn is_full_after_marking_all() {
160 let mut buf = [0u8; CoverageBuffer::bytes_for(4, 4)];
161 let mut cov = CoverageBuffer::new(&mut buf, 4, 4).unwrap();
162 assert!(!cov.is_full());
163 for y in 0..4 {
164 for x in 0..4 {
165 cov.mark_covered(x, y);
166 }
167 }
168 assert!(cov.is_full());
169 }
170
171 #[test]
172 fn out_of_bounds_is_covered_returns_false() {
173 let mut buf = [0u8; CoverageBuffer::bytes_for(4, 4)];
174 let cov = CoverageBuffer::new(&mut buf, 4, 4).unwrap();
175 assert!(!cov.is_covered(4, 0));
176 assert!(!cov.is_covered(0, 4));
177 assert!(!cov.is_covered(100, 100));
178 }
179}