osiris_display/display/
graphic.rs

1use std::f64::consts::PI;
2
3use osiris_data::data::atomic::Word;
4use osiris_data::data::composite::Array;
5use osiris_data::data::identification::Address;
6
7use osiris_typed::types::DataType;
8
9#[derive(Copy, Clone, Debug)]
10pub struct Pixel(u8);
11
12impl Pixel {
13    pub const BLACK: Self = Self::new(0, 0, 0, 3);
14    pub const DARK_GRAY: Self = Self::new(1, 1, 1, 3);
15    pub const LIGHT_GRAY: Self = Self::new(2, 2, 2, 3);
16    pub const WHITE: Self = Self::new(3, 3, 3, 3);
17    pub const RED: Self = Self::new(3, 0, 0, 3);
18    pub const GREEN: Self = Self::new(0, 3, 0, 3);
19    pub const BLUE: Self = Self::new(0, 0, 3, 3);
20    pub const YELLOW: Self = Self::new(3, 3, 0, 3);
21    pub const MAGENTA: Self = Self::new(3, 0, 3, 3);
22    pub const CYAN: Self = Self::new(0, 3, 3, 3);
23
24    pub fn add(&self, other: &Self) -> Self {
25        let (Self(s), Self(o)) = (self, other);
26        Self::raw(s | o)
27    }
28
29    pub fn subtract(&self, other: &Self) -> Self {
30        let (Self(s), Self(o)) = (self, other);
31        Self::raw(s & !o)
32    }
33
34    pub fn xor(&self, other: &Self) -> Self {
35        let (Self(s), Self(o)) = (self, other);
36        Self::raw(s ^ o)
37    }
38
39    pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
40        Self::new(r / 85, g / 85, b / 85, a / 85)
41    }
42
43    /// * `r`, `g` and `b` are returned by their encoded value `x85`
44    ///   * 0 -> 0,
45    ///   * 1 -> 85 (33.3%),
46    ///   * 2 -> 170 (66.6%),
47    ///   * 3 -> 255 (100%),
48    /// * `a` is multiplied by 85 too, but,
49    /// * `if a == 0 && {r, g, b} != 0`,
50    /// * then `a = 38` (15%).
51    pub fn to_rgba(&self) -> (u8, u8, u8, u8) {
52        let (r, g, b, a) = self.split();
53        let minimal_color_transparency = a == 0 && (r != 0 || g != 0 || b != 0);
54        (r * 85, g * 85, b * 85, if minimal_color_transparency { 38 } else { a * 85 })
55    }
56
57    pub fn split(&self) -> (u8, u8, u8, u8) {
58        let r = (self.0 & 0b11000000) >> 6;
59        let g = (self.0 & 0b00110000) >> 4;
60        let b = (self.0 & 0b00001100) >> 2;
61        let a = self.0 & 0b00000011;
62        (r, g, b, a)
63    }
64
65    /// `r`, `g`, `b` and `a` are base-4 digits.
66    pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
67        Self(r << 6 | g << 4 | b << 2 | a)
68    }
69
70    pub const fn raw(byte: u8) -> Self { Self(byte) }
71
72    pub fn from_word(word: Word) -> [Pixel; 8] { word.to_u64().to_be_bytes().map(Pixel::raw) }
73    pub fn pixels_to_word(from: &[Pixel; 8]) -> Word {
74        Word::new(u64::from_be_bytes(from.map(|p| p.0)))
75    }
76
77    pub const fn get(&self) -> u8 { self.0 }
78
79    /// Creates all combinations of 256 (4x4x4x4) colors.
80    pub fn create_all_colors() -> Vec<Self> {
81        let mut colors = Vec::new();
82        for r in 0..4 {
83            for g in 0..4 {
84                for b in 0..4 {
85                    for a in 0..4 {
86                        colors.push(Self::new(r, g, b, a))
87                    }
88                }
89            }
90        }
91        colors
92    }
93}
94
95impl Default for Pixel {
96    fn default() -> Self { Self::BLACK }
97}
98
99pub trait Draw<DrawnType> {
100    fn draw(&mut self, drawn: &DrawnType, x: usize, y: usize);
101}
102
103#[derive(Clone, Debug)]
104pub struct Image {
105    width: usize,
106    data: Vec<Pixel>,
107}
108
109impl Image {
110    pub fn square(width: usize, height: usize, color: Pixel) -> Self {
111        let mut data = Vec::new();
112        data.resize(width * height, color);
113        Self { width, data }
114    }
115
116    pub fn width(&self) -> usize { self.width }
117
118    pub fn height(&self) -> usize { self.data.len() / self.width }
119
120    pub fn from_array(array: Array) -> Option<Self> {
121        let mut data = Vec::new();
122        let width = array.next(&mut Address::new(0))?.to_u64() as usize;
123        for w in array.sub_from_end(Address::new(2)).as_slice() {
124            for p in Pixel::from_word(*w) {
125                data.push(p);
126            }
127        }
128
129        Some(Self{ width, data })
130    }
131}
132
133impl Draw<Pixel> for Image {
134    fn draw(&mut self, drawn: &Pixel, x: usize, y: usize) {
135        self.data[y * self.width + x] = *drawn;
136    }
137}
138
139impl Draw<Image> for Image {
140    fn draw(&mut self, drawn: &Image, x: usize, y: usize) {
141        for (source_row, target_row) in (y..(y + self.height())).enumerate() {
142            for (source_column, target_column) in (x..(x + self.width())).enumerate() {
143                self.draw(&drawn.data[source_row + drawn.width() + source_column], target_column, target_row);
144            }
145        }
146    }
147}
148
149impl DataType for Image {
150    fn typename(&self) -> String { "Image".to_string() }
151
152    fn size(&self) -> usize { self.to_array().len() }
153
154    fn to_array(&self) -> Array {
155        let mut array = Array::default();
156        array.push(Word::new((self.width() * self.height()) as u64));
157        array.push(Word::new(self.width() as u64));
158
159        let mut buffer = [Pixel::default(); 8];
160        let mut buffer_index = 0;
161        for pixel in self.data.iter() {
162            buffer[buffer_index] = *pixel;
163            buffer_index += 1;
164            if buffer_index == 8 {
165                buffer_index = 0;
166                array.push(Pixel::pixels_to_word(&buffer));
167            }
168        }
169        if buffer_index != 0 {
170            array.push(Pixel::pixels_to_word(&buffer));
171        }
172        array
173    }
174}
175
176
177#[derive(Clone, Debug)]
178pub struct Sprite {
179    x: usize,
180    y: usize,
181    angle: f64,
182    image: Image,
183}
184
185impl Sprite {
186    pub fn new(x: usize, y: usize, image: Image) -> Self {
187        Sprite { x, y, angle: 0.0, image }
188    }
189
190    pub fn translate(&mut self, x: usize, y: usize) {
191        self.x = x;
192        self.y = y;
193    }
194
195    pub fn rotate(&mut self, angle_delta: f64) {
196        self.angle = angle_delta % (2.0 * PI);
197    }
198
199    pub fn change(&mut self, image: Image) {
200        self.image = image;
201    }
202    
203    pub fn position(&self) -> (usize, usize) {
204        (self.x, self.y)
205    }
206    
207    pub fn angle(&self) -> f64 {
208        self.angle
209    }
210
211    pub fn image(&self) -> &Image { &self.image }
212
213    pub fn width(&self) -> usize { self.image.width() }
214
215    pub fn height(&self) -> usize { self.image.height() }
216}
217
218impl Draw<Image> for Sprite {
219    fn draw(&mut self, drawn: &Image, x: usize, y: usize) {
220        self.image.draw(drawn, x, y);
221    }
222}