micro_gui/core/
buffer.rs

1//! Buffer module creates a read write buffer from a reference to a data array.
2//!
3//! Copyright 2017 Ryan Kurte
4
5use std::*;
6
7use std::marker::PhantomData;
8
9use crate::types::pixel::{PixelBW, PixelRGB24};
10
11/// Buff trait encompasses methods required for a graphics buffer
12pub trait Buff<Pixel> {
13    /// Set trait sets a pixel in the buffer
14    fn set(&mut self, x: usize, y: usize, p: &Pixel);
15    /// Get trait fetches a pixel in a buffer
16    fn get(&self, x: usize, y: usize) -> Pixel;
17    /// Size trait fetches the size of a buffer (in pixels)
18    fn size(&self) -> (usize, usize);
19    /// Clear clears the buffer
20    fn clear(&mut self, p: &Pixel);
21}
22
23/// Buffer implements a generic display buffer over an arbitrary pixel type
24#[derive(Debug)]
25pub struct Buffer<'a, Pixel> {
26    pub width: usize,
27    pub height: usize,
28    pub porch_bytes: usize,
29    pub trailer_bytes: usize,
30    pub line_width_bytes: usize,
31    pub data: &'a mut [u8],
32    _pixel: PhantomData<Pixel>,
33}
34
35impl <'a, Pixel> Buffer <'a, Pixel> {
36    pub fn data(&self) -> &[u8] {
37        self.data
38    }
39}
40
41impl <'a> Buffer <'a, PixelBW> {
42    // Create a new black and white buffer
43    pub fn new(width: usize, height: usize, porch_bytes: usize, trailer_bytes: usize, data: &'a mut [u8]) -> Self {
44        let line_width_bytes = porch_bytes + width / 8 + trailer_bytes;
45        return Self{width, height, porch_bytes, trailer_bytes, line_width_bytes, data, _pixel: PhantomData}
46    }
47}
48
49impl <'a> Buff<PixelBW> for Buffer <'a, PixelBW> {
50    /// Black and white mode pixel set function
51    fn set(&mut self, x: usize, y: usize, p: &PixelBW) {
52        let index = self.line_width_bytes * y + self.porch_bytes + x / 8;
53        let mask = 1 << (7 - x % 8) as u8;
54
55        if *p {
56            self.data[index as usize] |= mask;
57        } else {
58            self.data[index as usize] &= !mask;
59        }
60    }
61
62    /// Black and white mode pixel get function
63    fn get(&self, x: usize, y: usize) -> PixelBW {
64        let index = self.line_width_bytes * y + self.porch_bytes + x / 8;
65        let mask = 1 << (7 - x % 8);
66
67        if (self.data[index as usize] & mask) != 0 {
68             return true;
69        } else {
70            return false;
71        }
72    }  
73
74    /// Black and White mode buffer clear function
75    fn clear(&mut self, p: &PixelBW) {
76        for y in 0..self.height {
77            for x in 0..self.width {
78                self.set(x, y, p);
79            }
80        }
81    } 
82
83    /// Fetch the buffer size in pixels
84    fn size(&self) -> (usize, usize) {
85        return (self.width, self.height);
86    }
87}
88
89impl <'a> Buffer <'a, PixelRGB24> {
90    // Create a new rgb24 buffer
91    pub fn new(width: usize, height: usize, porch_bytes: usize, trailer_bytes: usize, data: &'a mut [u8]) -> Self {
92        let line_width_bytes = porch_bytes + width * 3 + trailer_bytes;
93        return Self{width, height, porch_bytes, trailer_bytes, line_width_bytes, data, _pixel: PhantomData}
94    }
95}
96
97impl <'a> Buff<PixelRGB24> for Buffer <'a, PixelRGB24> {
98
99    /// RGB24 mode pixel set function
100    fn set(&mut self, x: usize, y: usize, p: &PixelRGB24) {
101        let index: usize = self.line_width_bytes * y + x * 3 + self.porch_bytes;
102        
103        self.data[index + 0] = p.r;
104        self.data[index + 1] = p.g;
105        self.data[index + 2] = p.b;
106    }
107
108    /// RGB24 mode pixel get function
109    fn get(&self, x: usize, y: usize) -> PixelRGB24 {
110        let index: usize = self.line_width_bytes * y + x * 3 + self.porch_bytes;
111
112        return PixelRGB24{
113            r: self.data[index + 0],
114            g: self.data[index + 1],
115            b: self.data[index + 2]} 
116    }
117
118    /// RGB24 mode buffer clear function
119    fn clear(&mut self, p: &PixelRGB24) {
120        for y in 0..self.height {
121            for x in 0..self.width {
122                self.set(x, y, p);
123            }
124        }
125    }
126
127    /// Fetch the buffer size in pixels
128    fn size(&self) -> (usize, usize) {
129        return (self.width, self.height);
130    }
131}
132
133
134/// Format implementation for the buffer
135impl <'a, Pixel>fmt::Display for Buffer<'a, Pixel> {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 
137        write!(f, "[width: {}px height: {}px porch: {}B trailer: {}B line_width: {}B Data:\n", 
138        self.width, self.height, self.porch_bytes, self.trailer_bytes, self.line_width_bytes).unwrap();
139        for l in 0..self.height {
140            let start: usize = l * self.line_width_bytes;
141            let end:   usize = start + self.line_width_bytes - 1;
142            write!(f, "\t\t{:?}\n", &self.data[start..end]).unwrap();
143        }
144        write!(f, "\t]\n").unwrap();
145        Ok(())
146     }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152
153    use crate::types::pixel::*;
154
155    const WIDTH: usize = 16;
156    const HEIGHT: usize = 16;
157    const PORCH: usize = 1;
158    const TRAILER: usize = 1;
159    const SIZE_BW: usize = (PORCH + WIDTH / 8 + TRAILER) * HEIGHT;
160    const SIZE_RGB24: usize = (PORCH + WIDTH * 3 + TRAILER) * HEIGHT;
161
162    #[test]
163    fn test_bw() {
164        let mut data: [u8; SIZE_BW] = [0; SIZE_BW];
165        let data_slice = &mut data[..];
166        let mut buffer = Buffer::<PixelBW>::new(WIDTH, HEIGHT, PORCH, TRAILER, data_slice);
167
168        buffer.set(0, 0, &true);
169        assert_eq!(buffer.get(0, 0), true);
170        assert_eq!(buffer.data[PORCH], 0x80);
171
172        buffer.set(0, 0, &false);
173        assert_eq!(buffer.get(0, 0), false);
174        assert_eq!(buffer.data[PORCH], 0x00);
175
176        buffer.set(1, 1, &true);
177        assert_eq!(buffer.get(1, 1), true);
178        assert_eq!(buffer.data[PORCH + WIDTH / 8 + TRAILER + PORCH], 0x40);
179
180        buffer.set(1, 1, &false);
181        assert_eq!(buffer.get(1, 1), false);
182        assert_eq!(buffer.data[PORCH + WIDTH / 8 + TRAILER + PORCH], 0x00);
183    }
184
185    #[test]
186    fn test_rgb24_porch_trailer() {
187        let mut data: [u8; SIZE_RGB24] = [0; SIZE_RGB24];
188        let data_slice = &mut data[..];
189
190        let blank: [u8; SIZE_RGB24] = [0; SIZE_RGB24];
191        let blank_slice = &blank[..];
192
193        let mut buffer = Buffer::<PixelRGB24>::new(WIDTH, HEIGHT, PORCH, TRAILER, data_slice);
194
195        buffer.set(0, 0, &PixelRGB24::white());
196        assert_eq!(buffer.get(0, 0), PixelRGB24::white());
197        assert_eq!(buffer.data[PORCH + 0], 0xFF);
198        assert_eq!(buffer.data[PORCH + 1], 0xFF);
199        assert_eq!(buffer.data[PORCH + 2], 0xFF);
200
201        buffer.set(0, 0, &PixelRGB24::black());
202        assert_eq!(buffer.get(0, 0), PixelRGB24::black());
203        assert_eq!(buffer.data, blank_slice);
204
205        buffer.set(1, 1, &PixelRGB24::white());
206        assert_eq!(buffer.get(1, 1), PixelRGB24::white());
207
208        let index: usize = (PORCH + WIDTH * 3 + TRAILER) + 3 + PORCH;
209        assert_eq!(buffer.data[index + 0], 0xFF);
210        assert_eq!(buffer.data[index + 1], 0xFF);
211        assert_eq!(buffer.data[index + 2], 0xFF);
212
213        buffer.set(1, 1, &PixelRGB24::black());
214        assert_eq!(buffer.get(1, 1), PixelRGB24::black());
215        assert_eq!(buffer.data, blank_slice);
216    }
217
218    const X: usize = 2;
219    const Y: usize = 2;
220
221    #[test]
222    fn test_rgb24_buffer() {
223        let mut data = [0u8; X * Y * 3];
224
225        let mut buffer = Buffer::<PixelRGB24>::new(X, Y, 0, 0, &mut data);
226
227        let white = PixelRGB24::white();
228        let black = PixelRGB24::black();
229
230        for y in 0..Y {
231            for x in 0..X {
232                buffer.clear(&white);
233
234                buffer.set(x, y, &black);
235                assert_eq!(buffer.get(x, y), black);
236
237                let index = (y * Y + x) * 3;
238                assert_eq!(buffer.data[index+0], 0x00);
239                assert_eq!(buffer.data[index+1], 0x00);
240                assert_eq!(buffer.data[index+2], 0x00);
241            }
242        }
243    }
244}
245