1use crate::color::{ColorType, TriColor};
4use core::marker::PhantomData;
5use embedded_graphics_core::prelude::*;
6
7#[derive(Clone, Copy, Default)]
9pub enum DisplayRotation {
10 #[default]
12 Rotate0,
13 Rotate90,
15 Rotate180,
17 Rotate270,
19}
20
21const fn line_bytes(width: u32, bits_per_pixel: usize) -> usize {
23 (width as usize * bits_per_pixel + 7) / 8
25}
26
27pub struct Display<
50 const WIDTH: u32,
51 const HEIGHT: u32,
52 const BWRBIT: bool,
53 const BYTECOUNT: usize,
54 COLOR: ColorType + PixelColor,
55> {
56 buffer: [u8; BYTECOUNT],
57 rotation: DisplayRotation,
58 _color: PhantomData<COLOR>,
59}
60
61impl<
62 const WIDTH: u32,
63 const HEIGHT: u32,
64 const BWRBIT: bool,
65 const BYTECOUNT: usize,
66 COLOR: ColorType + PixelColor,
67 > Default for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
68{
69 #[inline(always)]
78 fn default() -> Self {
79 Self {
80 buffer: [0u8; BYTECOUNT],
82 rotation: DisplayRotation::default(),
83 _color: PhantomData,
84 }
85 }
86}
87
88impl<
90 const WIDTH: u32,
91 const HEIGHT: u32,
92 const BWRBIT: bool,
93 const BYTECOUNT: usize,
94 COLOR: ColorType + PixelColor,
95 > DrawTarget for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
96{
97 type Color = COLOR;
98 type Error = core::convert::Infallible;
99
100 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
101 where
102 I: IntoIterator<Item = Pixel<Self::Color>>,
103 {
104 for pixel in pixels {
105 self.set_pixel(pixel);
106 }
107 Ok(())
108 }
109}
110
111impl<
113 const WIDTH: u32,
114 const HEIGHT: u32,
115 const BWRBIT: bool,
116 const BYTECOUNT: usize,
117 COLOR: ColorType + PixelColor,
118 > OriginDimensions for Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
119{
120 fn size(&self) -> Size {
121 match self.rotation {
122 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => Size::new(WIDTH, HEIGHT),
123 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => Size::new(HEIGHT, WIDTH),
124 }
125 }
126}
127
128impl<
129 const WIDTH: u32,
130 const HEIGHT: u32,
131 const BWRBIT: bool,
132 const BYTECOUNT: usize,
133 COLOR: ColorType + PixelColor,
134 > Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, COLOR>
135{
136 pub fn buffer(&self) -> &[u8] {
138 &self.buffer
139 }
140
141 pub fn set_rotation(&mut self, rotation: DisplayRotation) {
146 self.rotation = rotation;
147 }
148
149 pub fn rotation(&self) -> DisplayRotation {
151 self.rotation
152 }
153
154 pub fn set_pixel(&mut self, pixel: Pixel<COLOR>) {
156 set_pixel(
157 &mut self.buffer,
158 WIDTH,
159 HEIGHT,
160 self.rotation,
161 BWRBIT,
162 pixel,
163 );
164 }
165}
166
167impl<const WIDTH: u32, const HEIGHT: u32, const BWRBIT: bool, const BYTECOUNT: usize>
169 Display<WIDTH, HEIGHT, BWRBIT, BYTECOUNT, TriColor>
170{
171 pub fn bw_buffer(&self) -> &[u8] {
173 &self.buffer[..self.buffer.len() / 2]
174 }
175
176 pub fn chromatic_buffer(&self) -> &[u8] {
178 &self.buffer[self.buffer.len() / 2..]
179 }
180}
181
182pub struct VarDisplay<'a, COLOR: ColorType + PixelColor> {
186 width: u32,
187 height: u32,
188 bwrbit: bool,
189 buffer: &'a mut [u8],
190 rotation: DisplayRotation,
191 _color: PhantomData<COLOR>,
192}
193
194impl<'a, COLOR: ColorType + PixelColor> DrawTarget for VarDisplay<'a, COLOR> {
196 type Color = COLOR;
197 type Error = core::convert::Infallible;
198
199 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
200 where
201 I: IntoIterator<Item = Pixel<Self::Color>>,
202 {
203 for pixel in pixels {
204 self.set_pixel(pixel);
205 }
206 Ok(())
207 }
208}
209
210impl<'a, COLOR: ColorType + PixelColor> OriginDimensions for VarDisplay<'a, COLOR> {
212 fn size(&self) -> Size {
213 match self.rotation {
214 DisplayRotation::Rotate0 | DisplayRotation::Rotate180 => {
215 Size::new(self.width, self.height)
216 }
217 DisplayRotation::Rotate90 | DisplayRotation::Rotate270 => {
218 Size::new(self.height, self.width)
219 }
220 }
221 }
222}
223
224#[derive(Debug)]
226pub enum VarDisplayError {
227 BufferTooSmall,
229}
230
231impl<'a, COLOR: ColorType + PixelColor> VarDisplay<'a, COLOR> {
232 pub fn new(
237 width: u32,
238 height: u32,
239 buffer: &'a mut [u8],
240 bwrbit: bool,
241 ) -> Result<Self, VarDisplayError> {
242 let myself = Self {
243 width,
244 height,
245 bwrbit,
246 buffer,
247 rotation: DisplayRotation::default(),
248 _color: PhantomData,
249 };
250 if myself.buffer_size() > myself.buffer.len() {
252 return Err(VarDisplayError::BufferTooSmall);
253 }
254 Ok(myself)
255 }
256
257 fn buffer_size(&self) -> usize {
259 self.height as usize
260 * line_bytes(
261 self.width,
262 COLOR::BITS_PER_PIXEL_PER_BUFFER * COLOR::BUFFER_COUNT,
263 )
264 }
265
266 pub fn buffer(&self) -> &[u8] {
268 &self.buffer[..self.buffer_size()]
269 }
270
271 pub fn set_rotation(&mut self, rotation: DisplayRotation) {
276 self.rotation = rotation;
277 }
278
279 pub fn rotation(&self) -> DisplayRotation {
281 self.rotation
282 }
283
284 pub fn set_pixel(&mut self, pixel: Pixel<COLOR>) {
286 let size = self.buffer_size();
287 set_pixel(
288 &mut self.buffer[..size],
289 self.width,
290 self.height,
291 self.rotation,
292 self.bwrbit,
293 pixel,
294 );
295 }
296}
297
298impl<'a> VarDisplay<'a, TriColor> {
300 pub fn bw_buffer(&self) -> &[u8] {
302 &self.buffer[..self.buffer_size() / 2]
303 }
304
305 pub fn chromatic_buffer(&self) -> &[u8] {
307 &self.buffer[self.buffer_size() / 2..self.buffer_size()]
308 }
309}
310
311fn set_pixel<COLOR: ColorType + PixelColor>(
316 buffer: &mut [u8],
317 width: u32,
318 height: u32,
319 rotation: DisplayRotation,
320 bwrbit: bool,
321 pixel: Pixel<COLOR>,
322) {
323 let Pixel(point, color) = pixel;
324
325 let (x, y) = match rotation {
327 DisplayRotation::Rotate0 => (point.x, point.y),
329 DisplayRotation::Rotate90 => (width as i32 - 1 - point.y, point.x),
330 DisplayRotation::Rotate180 => (width as i32 - 1 - point.x, height as i32 - 1 - point.y),
331 DisplayRotation::Rotate270 => (point.y, height as i32 - 1 - point.x),
332 };
333
334 if (x < 0) || (x >= width as i32) || (y < 0) || (y >= height as i32) {
336 return;
338 }
339
340 let index = x as usize * COLOR::BITS_PER_PIXEL_PER_BUFFER / 8
341 + y as usize * line_bytes(width, COLOR::BITS_PER_PIXEL_PER_BUFFER);
342 let (mask, bits) = color.bitmask(bwrbit, x as u32);
343
344 if COLOR::BUFFER_COUNT == 2 {
345 buffer[index] = buffer[index] & mask | (bits & 0xFF) as u8;
347 let index = index + buffer.len() / 2;
348 buffer[index] = buffer[index] & mask | (bits >> 8) as u8;
349 } else {
350 buffer[index] = buffer[index] & mask | bits as u8;
351 }
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357 use crate::color::*;
358 use embedded_graphics::{
359 prelude::*,
360 primitives::{Line, PrimitiveStyle},
361 };
362
363 #[test]
365 fn graphics_size() {
366 let display = Display::<200, 200, false, { 200 * 200 / 8 }, Color>::default();
368 assert_eq!(display.buffer().len(), 5000);
369 }
370
371 #[test]
373 fn graphics_default() {
374 let display = Display::<200, 200, false, { 200 * 200 / 8 }, Color>::default();
375 for &byte in display.buffer() {
376 assert_eq!(byte, 0);
377 }
378 }
379
380 #[test]
381 fn graphics_rotation_0() {
382 let mut display = Display::<200, 200, false, { 200 * 200 / 8 }, Color>::default();
383 let _ = Line::new(Point::new(0, 0), Point::new(7, 0))
384 .into_styled(PrimitiveStyle::with_stroke(Color::Black, 1))
385 .draw(&mut display);
386
387 let buffer = display.buffer();
388
389 assert_eq!(buffer[0], Color::Black.get_byte_value());
390
391 for &byte in buffer.iter().skip(1) {
392 assert_eq!(byte, 0);
393 }
394 }
395
396 #[test]
397 fn graphics_rotation_90() {
398 let mut display = Display::<200, 200, false, { 200 * 200 / 8 }, Color>::default();
399 display.set_rotation(DisplayRotation::Rotate90);
400 let _ = Line::new(Point::new(0, 192), Point::new(0, 199))
401 .into_styled(PrimitiveStyle::with_stroke(Color::Black, 1))
402 .draw(&mut display);
403
404 let buffer = display.buffer();
405
406 assert_eq!(buffer[0], Color::Black.get_byte_value());
407
408 for &byte in buffer.iter().skip(1) {
409 assert_eq!(byte, 0);
410 }
411 }
412
413 #[test]
414 fn graphics_rotation_180() {
415 let mut display = Display::<200, 200, false, { 200 * 200 / 8 }, Color>::default();
416 display.set_rotation(DisplayRotation::Rotate180);
417 let _ = Line::new(Point::new(192, 199), Point::new(199, 199))
418 .into_styled(PrimitiveStyle::with_stroke(Color::Black, 1))
419 .draw(&mut display);
420
421 let buffer = display.buffer();
422
423 extern crate std;
424 std::println!("{:?}", buffer);
425
426 assert_eq!(buffer[0], Color::Black.get_byte_value());
427
428 for &byte in buffer.iter().skip(1) {
429 assert_eq!(byte, 0);
430 }
431 }
432
433 #[test]
434 fn graphics_rotation_270() {
435 let mut display = Display::<200, 200, false, { 200 * 200 / 8 }, Color>::default();
436 display.set_rotation(DisplayRotation::Rotate270);
437 let _ = Line::new(Point::new(199, 0), Point::new(199, 7))
438 .into_styled(PrimitiveStyle::with_stroke(Color::Black, 1))
439 .draw(&mut display);
440
441 let buffer = display.buffer();
442
443 extern crate std;
444 std::println!("{:?}", buffer);
445
446 assert_eq!(buffer[0], Color::Black.get_byte_value());
447
448 for &byte in buffer.iter().skip(1) {
449 assert_eq!(byte, 0);
450 }
451 }
452}