1use std::cmp::Ordering;
2
3fn expand(n: u8) -> u16 {
7 let mut result: u16 = 0;
8 for i in 0..8 {
9 result |= (n as u16 & (1 << i)) << i
10 }
11 result | (result << 1)
12}
13
14#[inline(always)]
15pub fn get_px(d: &[u128; 64], x: usize, y: usize) -> bool {
16 let (shifted, _) = d[y].overflowing_shr(127 - x as u32);
17 (shifted & 1) == 1
18}
19
20pub struct Display {
21 d: Box<[u128; 64]>,
22 hi_res: bool,
23 dirty: bool,
24}
25
26impl Display {
27 pub fn new() -> Display {
28 Display {
29 d: Box::new([0; 64]),
30 hi_res: false,
31 dirty: false,
32 }
33 }
34
35 pub fn hi_res_mode(&mut self) {
36 self.hi_res = true
37 }
38
39 pub fn low_res_mode(&mut self) {
40 self.hi_res = false
41 }
42
43 pub fn scroll_down(&mut self, n: u32) {
44 let n = n as usize;
45 self.dirty = true;
46 self.d.copy_within(..64-n, n);
47 for i in 0..n {
48 self.d[i] = 0
49 }
50 }
51
52 #[allow(arithmetic_overflow)]
53 pub fn scroll_side(&mut self, n: i32) {
54 self.dirty = true;
55 for row in &mut *self.d {
56 match n.cmp(&0) {
57 Ordering::Greater => *row >>= n,
58 Ordering::Less => *row <<= n.abs(),
59 Ordering::Equal => {},
60 }
61 }
62 }
63
64 pub fn clear(&mut self) {
65 self.dirty = true;
66 self.d = Box::new([0; 64])
67 }
68
69 pub fn write(&mut self, b: u8, mut x: usize, mut y: usize) -> bool {
70 let b = if !self.hi_res {
71 x *= 2;
72 y *= 2;
73 expand(b)
74 } else {
75 (b as u16) << 8
76 };
77
78 let x = x % 128;
79 let y = y % 64;
80
81 let mut erased = false;
82 self.dirty = true;
83 let mut b = (b as u128) << 112;
84 b = b.rotate_right(x as u32);
85
86 if b & self.d[y] != 0 {
87 erased = true
88 };
89 self.d[y] ^= b;
90
91 if !self.hi_res {
92 if b & self.d[y + 1] != 0 {
93 erased = true
94 };
95 self.d[y + 1] ^= b;
96 }
97
98 erased
99 }
100
101 pub fn read(&mut self) -> &[u128; 64] {
102 self.dirty = false;
103 &self.d
104 }
105
106 pub fn read_px(&mut self, x: usize, y: usize) -> bool {
107 self.dirty = false;
108 get_px(&self.d, x, y)
109 }
110
111 pub fn hi_res(&self) -> bool {
112 self.hi_res
113 }
114
115 pub fn dirty(&self) -> bool {
116 self.dirty
117 }
118}
119
120impl Default for Display {
121 fn default() -> Self {
122 Display::new()
123 }
124}
125
126pub const DEFAULT_FONT: [u8; 240] = [
127 0xF0, 0x90, 0x90, 0x90, 0xF0, 0x20, 0x60, 0x20, 0x20, 0x70, 0xF0, 0x10, 0xF0, 0x80, 0xF0, 0xF0, 0x10, 0xF0, 0x10, 0xF0, 0x90, 0x90, 0xF0, 0x10, 0x10, 0xF0, 0x80, 0xF0, 0x10, 0xF0, 0xF0, 0x80, 0xF0, 0x90, 0xF0, 0xF0, 0x10, 0x20, 0x40, 0x40, 0xF0, 0x90, 0xF0, 0x90, 0xF0, 0xF0, 0x90, 0xF0, 0x10, 0xF0, 0xF0, 0x90, 0xF0, 0x90, 0x90, 0xE0, 0x90, 0xe0, 0x90, 0xE0, 0xF0, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x90, 0x90, 0x90, 0xE0, 0xF0, 0x80, 0xF0, 0x80, 0xF0, 0xF0, 0x80, 0xF0, 0x80, 0x80, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0x18, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x03, 0x06, 0x0C, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xC3, 0xC3, 0xFF, 0xFF, 0x03, 0x03, 0xFF, 0xFF, 0x7E, 0xFF, 0xC3, 0xC3, 0xC3, 0xFF, 0xFF, 0xC3, 0xC3, 0xC3, 0xFC, 0xFC, 0xC3, 0xC3, 0xFC, 0xFC, 0xC3, 0xC3, 0xFC, 0xFC, 0x3C, 0xFF, 0xC3, 0xC0, 0xC0, 0xC0, 0xC0, 0xC3, 0xFF, 0x3C, 0xFC, 0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xFE, 0xFC, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xC0, 0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, ];