summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/screen.rs219
1 files changed, 100 insertions, 119 deletions
diff --git a/src/devices/screen.rs b/src/devices/screen.rs
index ee11f52..c96d1c4 100644
--- a/src/devices/screen.rs
+++ b/src/devices/screen.rs
@@ -257,28 +257,28 @@ impl ScreenDevice {
}
fn draw_line(&mut self, colour: u8, layer: ScreenLayer) {
- let points = self.vector.get_pair();
- match (points[0].x == points[1].x, points[0].y == points[1].y) {
- (false, false) => self.draw_diagonal_line(colour, layer, points),
- (false, true) => self.draw_horizontal_line(colour, layer, points),
- ( true, false) => self.draw_vertical_line(colour, layer, points),
- ( true, true) => self.draw_pixel(colour, layer, points[0]),
+ let [p0, p1] = self.vector.get_pair();
+ match (p0.x == p1.x, p0.y == p1.y) {
+ (false, false) => self.draw_diagonal_line(colour, layer),
+ (false, true) => self.draw_horizontal_line(colour, layer),
+ ( true, false) => self.draw_vertical_line(colour, layer),
+ ( true, true) => self.draw_pixel(colour, layer, p0),
};
}
- fn draw_diagonal_line(&mut self, colour: u8, layer: ScreenLayer, points: [ScreenPosition; 2]) {
+ fn draw_diagonal_line(&mut self, colour: u8, layer: ScreenLayer) {
fn abs_diff(v0: u16, v1: u16) -> u16 {
let v = v1.wrapping_sub(v0);
if v > 0x8000 { !v + 1 } else { v }
}
- let [p0, p1] = points;
+ let [p0, p1] = self.vector.get_pair();
// If the slope of the line is greater than 1.
if abs_diff(p0.y, p1.y) > abs_diff(p0.x, p1.x) {
// Swap points 0 and 1 so that y0 is always smaller than y1.
- let (x0, y0, x1, y1) = match points[0].y > points[1].y {
- true => (points[1].x, points[1].y, points[0].x, points[0].y),
- false => (points[0].x, points[0].y, points[1].x, points[1].y),
+ let (x0, y0, x1, y1) = match p0.y > p1.y {
+ true => (p1.x, p1.y, p0.x, p0.y),
+ false => (p0.x, p0.y, p1.x, p1.y),
};
let dy = y1 - y0;
@@ -303,9 +303,9 @@ impl ScreenDevice {
// If the slope of the line is less than or equal to 1.
} else {
// Swap points 0 and 1 so that x0 is always smaller than x1.
- let (x0, y0, x1, y1) = match points[0].x > points[1].x {
- true => (points[1].x, points[1].y, points[0].x, points[0].y),
- false => (points[0].x, points[0].y, points[1].x, points[1].y),
+ let (x0, y0, x1, y1) = match p0.x > p1.x {
+ true => (p1.x, p1.y, p0.x, p0.y),
+ false => (p0.x, p0.y, p1.x, p1.y),
};
let dx = x1 - x0;
@@ -330,125 +330,82 @@ impl ScreenDevice {
}
}
- fn draw_horizontal_line(&mut self, colour: u8, layer: ScreenLayer, points: [ScreenPosition; 2]) {
- let [start, end] = points;
- let dim = self.dimensions;
- let x0 = min(start.x, end.x);
- let x1 = max(start.x, end.x);
- if (x0 >= dim.width && x1 >= dim.width) || start.y >= dim.height { return }
- let x0 = min(x0, dim.width.saturating_sub(1));
- let x1 = min(x1, dim.width.saturating_sub(1));
- let row_i = (dim.width as usize) * (start.y as usize);
- let start_i = row_i + x0 as usize;
- let end_i = row_i + x1 as usize;
- let layer = match layer {
- ScreenLayer::Background => &mut self.background,
- ScreenLayer::Foreground => &mut self.foreground,
- };
- layer[start_i..=end_i].fill(colour);
- return
+ fn draw_horizontal_line(&mut self, colour: u8, layer: ScreenLayer) {
+ if let Some([x0, y, x1, _]) = self.find_vector_bounding_box() {
+ let screen_width = self.dimensions.width as usize;
+ let i = screen_width * y;
+ let layer = match layer {
+ ScreenLayer::Background => &mut self.background,
+ ScreenLayer::Foreground => &mut self.foreground,
+ };
+ layer[i+x0..=i+x1].fill(colour);
+ }
}
- fn draw_vertical_line(&mut self, colour: u8, layer: ScreenLayer, points: [ScreenPosition; 2]) {
- let [start, end] = points;
- let dim = self.dimensions;
- let y0 = min(start.y, end.y);
- let y1 = max(start.y, end.y);
- if (y0 >= dim.height && y1 >= dim.height) || start.x >= dim.width { return }
- let y0 = min(y0, dim.height.saturating_sub(1));
- let y1 = min(y1, dim.height.saturating_sub(1));
- let mut i = (start.x as usize) + (dim.width as usize * (y0 as usize));
- let pixels = match layer {
- ScreenLayer::Background => &mut self.background,
- ScreenLayer::Foreground => &mut self.foreground,
- };
- for _ in y0..=y1 {
- pixels[i] = colour;
- i += dim.width as usize;
+ fn draw_vertical_line(&mut self, colour: u8, layer: ScreenLayer) {
+ if let Some([x, y0, _, y1]) = self.find_vector_bounding_box() {
+ let screen_width = self.dimensions.width as usize;
+ let mut i = (screen_width * y0) + x;
+ let layer = match layer {
+ ScreenLayer::Background => &mut self.background,
+ ScreenLayer::Foreground => &mut self.foreground,
+ };
+ for _ in y0..=y1 {
+ layer[i] = colour;
+ i += screen_width;
+ }
+
}
- return
}
fn draw_rect(&mut self, colour: u8, layer: ScreenLayer) {
- let [x0, y0, x1, y1] = {
- macro_rules! raise {($v:expr) => {$v.wrapping_add(0x8000)};}
- macro_rules! lower {($v:expr) => {$v.wrapping_sub(0x8000)};}
- let [p0, p1] = self.vector.get_pair();
- let [p0x, p0y] = [ raise!(p0.x), raise!(p0.y) ];
- let [p1x, p1y] = [ raise!(p1.x), raise!(p1.y) ];
- let [x0, y0] = [ min(p0x, p1x), min(p0y, p1y) ];
- let [x1, y1] = [ max(p0x, p1x), max(p0y, p1y) ];
- let right = self.dimensions.width.saturating_sub(1);
- let bottom = self.dimensions.height.saturating_sub(1);
- if x0 > raise!(right) || y0 > raise!(bottom) || x1 < 0x8000 || y1 < 0x8000 { return }
- [
- if x0 < 0x8000 { 0 } else { min(lower!(x0), right) } as usize,
- if y0 < 0x8000 { 0 } else { min(lower!(y0), bottom) } as usize,
- if x1 < 0x8000 { 0 } else { min(lower!(x1), right) } as usize,
- if y1 < 0x8000 { 0 } else { min(lower!(y1), bottom) } as usize,
- ]
- };
- let screen_width = self.dimensions.width as usize;
- let rect_width = x1 - x0 + 1;
- let mut i = x0 + (screen_width * y0);
- let pixels = match layer {
- ScreenLayer::Background => &mut self.background,
- ScreenLayer::Foreground => &mut self.foreground,
- };
- for _ in y0..=y1 {
- pixels[i..i+rect_width].fill(colour);
- i += screen_width;
+ if let Some([x0, y0, x1, y1]) = self.find_vector_bounding_box() {
+ let screen_width = self.dimensions.width as usize;
+ let rect_width = x1 - x0 + 1;
+ let mut i = x0 + (screen_width * y0);
+ let pixels = match layer {
+ ScreenLayer::Background => &mut self.background,
+ ScreenLayer::Foreground => &mut self.foreground,
+ };
+ for _ in y0..=y1 {
+ pixels[i..i+rect_width].fill(colour);
+ i += screen_width;
+ }
}
}
fn draw_rect_1bit(&mut self, params: u8, layer: ScreenLayer) {
- let [x0, y0, x1, y1] = {
- macro_rules! raise {($v:expr) => {$v.wrapping_add(0x8000)};}
- macro_rules! lower {($v:expr) => {$v.wrapping_sub(0x8000)};}
- let [p0, p1] = self.vector.get_pair();
- let [p0x, p0y] = [ raise!(p0.x), raise!(p0.y) ];
- let [p1x, p1y] = [ raise!(p1.x), raise!(p1.y) ];
- let [x0, y0] = [ min(p0x, p1x), min(p0y, p1y) ];
- let [x1, y1] = [ max(p0x, p1x), max(p0y, p1y) ];
- let right = self.dimensions.width.saturating_sub(1);
- let bottom = self.dimensions.height.saturating_sub(1);
- if x0 > raise!(right) || y0 > raise!(bottom) || x1 < 0x8000 || y1 < 0x8000 { return }
- [
- if x0 < 0x8000 { 0 } else { min(lower!(x0), right) } as usize,
- if y0 < 0x8000 { 0 } else { min(lower!(y0), bottom) } as usize,
- if x1 < 0x8000 { 0 } else { min(lower!(x1), right) } as usize,
- if y1 < 0x8000 { 0 } else { min(lower!(y1), bottom) } as usize,
- ]
- };
- let screen_width = self.dimensions.width as usize;
- let rect_width = x1 - x0 + 1;
- let mut i = x0 + (screen_width * y0);
- let pixels = match layer {
- ScreenLayer::Background => &mut self.background,
- ScreenLayer::Foreground => &mut self.foreground,
- };
+ if let Some([x0, y0, x1, y1]) = self.find_vector_bounding_box() {
+ let screen_width = self.dimensions.width as usize;
+ let rect_width = x1 - x0 + 1;
+ let mut i = x0 + (screen_width * y0);
+ let pixels = match layer {
+ ScreenLayer::Background => &mut self.background,
+ ScreenLayer::Foreground => &mut self.foreground,
+ };
- let sprite_data = self.sprite_data.get_1bit_sprite();
- let mut sprite_i = y0 % 8;
- let sprite_x_off = (x0 % 8) as u32;
- let transparent = params & 0x08 != 0;
- if params & 0x07 != 0 {
- todo!("Pre-treat sprite, with rotation/translation");
- }
+ let sprite_data = self.sprite_data.get_1bit_sprite();
+ let mut sprite_i = y0 % 8;
+ let sprite_x_off = (x0 % 8) as u32;
+ let transparent = params & 0x08 != 0;
+ if params & 0x07 != 0 {
+ todo!("Pre-treat sprite, with rotation/translation");
+ }
- for _ in y0..=y1 {
- let mut row = sprite_data[sprite_i].rotate_left(sprite_x_off);
- for _ in x0..=x1 {
- let colour = (row >> 7) as usize;
- if !(transparent && colour == 0) {
- pixels[i] = self.sprite_colours[colour];
+ for _ in y0..=y1 {
+ let mut row = sprite_data[sprite_i].rotate_left(sprite_x_off);
+ for _ in x0..=x1 {
+ let colour = (row >> 7) as usize;
+ if !(transparent && colour == 0) {
+ pixels[i] = self.sprite_colours[colour];
+ }
+ row = row.rotate_left(1);
+ i += 1;
}
- row = row.rotate_left(1);
- i += 1;
+ sprite_i = (sprite_i + 1) % 8;
+ i += screen_width - rect_width;
}
- sprite_i = (sprite_i + 1) % 8;
- i += screen_width - rect_width;
- }
+ };
}
fn draw_sprite(&mut self, params: u8, layer: ScreenLayer, sprite: [u8; 64]) {
@@ -484,4 +441,28 @@ impl ScreenDevice {
_ => unreachable!(),
}
}
+
+ /// Returns [x0, y0, x1, y1]
+ fn find_vector_bounding_box(&self) -> Option<[usize; 4]> {
+ macro_rules! raise {($v:expr) => {$v.wrapping_add(0x8000)};}
+ macro_rules! lower {($v:expr) => {$v.wrapping_sub(0x8000)};}
+
+ let [p0, p1] = self.vector.get_pair();
+ let [p0x, p0y] = [ raise!(p0.x), raise!(p0.y) ];
+ let [p1x, p1y] = [ raise!(p1.x), raise!(p1.y) ];
+ let [x0, y0] = [ min(p0x, p1x), min(p0y, p1y) ];
+ let [x1, y1] = [ max(p0x, p1x), max(p0y, p1y) ];
+ let right = self.dimensions.width.saturating_sub(1);
+ let bottom = self.dimensions.height.saturating_sub(1);
+ if x0 > raise!(right) || y0 > raise!(bottom) || x1 < 0x8000 || y1 < 0x8000 {
+ None
+ } else {
+ Some([
+ if x0 < 0x8000 { 0 } else { min(lower!(x0), right) } as usize,
+ if y0 < 0x8000 { 0 } else { min(lower!(y0), bottom) } as usize,
+ if x1 < 0x8000 { 0 } else { min(lower!(x1), right) } as usize,
+ if y1 < 0x8000 { 0 } else { min(lower!(y1), bottom) } as usize,
+ ])
+ }
+ }
}