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 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 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 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}